invalid number of rows in section 0 - ios

I have a thread problem SIGABRT when i try to add one more cell in my app; That is the exception which Xcode gave me:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
That is the code where i consider is the problem
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PlayerCell *cell = (PlayerCell *)[tableView
dequeueReusableCellWithIdentifier:#"PlayerCell"];
Player *player = [self.players objectAtIndex:indexPath.row];
cell.nameLabel.text = player.name;
cell.gameLabel.text = player.game;
cell.ratingImageView.image = [self
imageForRating:player.rating];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.players removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; }
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.players count];
}
UPD.
I have an array in AppDelegate to preconfig several cells (to show user, how it looks like) and full it with follow code:
_players = [NSMutableArray arrayWithCapacity:20]; // make an array in appdelegate
Player *player = [[Player alloc] init]; //
player.name = #"Bill Evans"; //
player.game = #"Tic-Tac-Toe"; //Make new player
player.rating = 4; //
[_players addObject:player]; //Add in array in AppDelegate
PlayersViewController *playersViewController = [PlayersViewController new]; //Make instance for main array
playersViewController.players = _players; //add new item from appDelegate array to main
Another piece of code where the mistake may be (it loads when user taps on save button to add new cell)
- (void)playerDetailsViewController:
(PlayerDetailsViewController *)controller
didAddPlayer:(Player *)player
{
[self.players addObject:player];
NSIndexPath *indexPath =
[NSIndexPath indexPathForRow:[self.players count] - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:
[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self dismissViewControllerAnimated:YES completion:nil];
}
So can anyone tell me, where is my mistake? If needed, i can send further code.
Thanks.

Related

UITableView deleteRowsAtIndexPaths crash

I have UITableView and I made implementation for -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath :
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSUInteger beforeDeleteCount = historyArray.count;
VideoItem *video = [historyArray objectAtIndex:indexPath.row];
[[HistoryRepository sharedHistory] removeFromHistories:video];
if (self.titleSort) {
[self sortArrayByTitleAtoZWithReloadData:NO];
} else {
[self sortArrayByNormalWithReloadData:NO];
}
NSUInteger afterDeleteCount = historyArray.count;
if (beforeDeleteCount == afterDeleteCount) {
[table reloadData];
} else {
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
}
-(void)sortArrayByNormalWithReloadData:(BOOL)reload {
self.titleSort = NO;
historyArray = [[NSMutableArray alloc] initWithArray:[[HistoryRepository sharedHistory] historyArray]];
if (reload) {
[self setTableHeader];
[table reloadData];
}
}
-(void)sortArrayByTitleAtoZWithReloadData:(BOOL)reload {
self.titleSort = YES;
NSSortDescriptor * sortDescriptor = [[[NSSortDescriptor alloc]initWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)] autorelease];
historyArray = [[NSMutableArray alloc] initWithArray:[[[HistoryRepository sharedHistory] historyArray] sortedArrayUsingDescriptors:#[sortDescriptor]]];
if (reload) {
[self setTableHeader];
[table reloadData];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [historyArray count];
}
And I still get this kind of error all the time:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (27) must be equal to the number of rows contained in that section before the update (27), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
I always making a check if it's the same count so reload the table and don't delete but still i'm getting this error.
Reordering the data source array after deleting an item makes no sense if the array is already sorted.
And you must not call deleteRowsAtIndexPaths after reordering the data source array anyway.
This version of commitEditingStyle: is sufficient
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
VideoItem *video = [historyArray objectAtIndex:indexPath.row];
[[HistoryRepository sharedHistory] removeFromHistories:video];
[historyArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}

Problem with adding a new row and populating it

I am trying to add a new row to my custom cell with an NSMutablearray from another viewcontroller but I am getting an error when a new row is added. itemsTableView is visible in photoCaptureView which is the view for photoCaptureViewController. So when ScannerModalViewController (which is being called also in photoCaptureViewController) is called and capture the item/data and once it is dismissed scannedBarcode is called to add a new row to my custom cell and populate it I'm getting this error.
I am getting a warning and an error. The warning is
Warning once only: UITableView was told to layout its visible cells and other contents without
being in the view hierarchy (the table view or one of its superviews has not been added to a
window). This may cause bugs by forcing views inside the table view to load and perform layout
without accurate information (e.g. table view bounds, trait collection, layout margins, safe
area insets, etc), and will also cause unnecessary performance overhead due to extra layout
passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch
this in the debugger and see what caused this to occur, so you can avoid this action altogether
if possible, or defer it until the table view has been added to a window. Table view:
<UITableView: 0x1038a9c00; frame = (10 70; 398 794); clipsToBounds = YES; gestureRecognizers =
<NSArray: 0x28165f0c0>; layer = <CALayer: 0x2818ebb20>; contentOffset: {0, 0}; contentSize:
{398, 60}; adjustedContentInset: {0, 0, 0, 0}; dataSource: <PhotoCaptureViewController: 0x10364a880>>
error is
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing
section after the update (3) must be equal to the number of rows contained in that section
before the update (1), plus or minus the number of rows inserted or deleted from that section
(1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section
(0 moved in, 0 moved out).
My code is photoCaptureViewController.h
#interface PhotoCaptureViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, ScannerModalViewControllerDelegate> {
PhotoCaptureView* photoCaptureView;
NSMutableArray* barcodeItems;
ScannerModalViewController* scannerModalViewController;
}
-(void) scanBarcode;
-(void) scannedBarcode:(NSString *) barcode;
#end
photoCaptureViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[photoCaptureView.itemsTableView registerNib:[UINib nibWithNibName:#"BarcodeItemsTableViewCell" bundle:nil] forCellReuseIdentifier:#"BarcodeItemsCell"];
photoCaptureView.itemsTableView.rowHeight = 60;
photoCaptureView.itemsTableView.dataSource = self;
photoCaptureView.itemsTableView.delegate = self;
[photoCaptureView.itemsTableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
}
#pragma mark scannerModalViewController Methods
-(void) scanBarcode {
NSLog(#"[%#] Scan Barcode Requested", self.class);
scannerModalViewController = [[ScannerModalViewController alloc] init];
scannerModalViewController.delegate = self;
scannerModalViewController.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:scannerModalViewController animated:YES completion:nil];
}
-(void) scannedBarcode:(NSMutableArray *) barcodes {
barcodeItems = [[NSMutableArray alloc] init];
[barcodeItems addObjectsFromArray:barcodes];
[barcodeItems addObject:#"test"];
[barcodeItems addObject:#"test1"];
NSLog(#"%#", barcodes);
NSLog(#"%#", barcodeItems);
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:barcodeItems.count-1 inSection:0];
[photoCaptureView.itemsTableView beginUpdates];
[photoCaptureView.itemsTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[photoCaptureView.itemsTableView endUpdates];
}
#pragma mark UITableViewDataSource methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return barcodeItems.count + 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Cell Initialized");
static NSString *cellIdentifier = #"BarcodeItemsCell";
BarcodeItemsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if (cell == nil) {
cell = [[BarcodeItemsTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
// Configure the cell...
cell.barcodeLabel.text = [barcodeItems objectAtIndex:indexPath.row];
UIImage *btnImage = [UIImage imageNamed:#"barcodeIcon"];
[cell.leftButton setImage:btnImage forState:UIControlStateNormal];
NSLog(#"Cell Populated");
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
return true;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[barcodeItems removeObjectAtIndex:indexPath.row];
[photoCaptureView.itemsTableView beginUpdates];
[photoCaptureView.itemsTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[photoCaptureView.itemsTableView endUpdates];
}
}
#end
If you insert the items with insertRowsAtIndexPaths you have to specify all paths.
And beginUpdates /endUpdates` has no effect for a single insert/delete/move operation.
-(void) scannedBarcode:(NSMutableArray *) barcodes {
barcodeItems = [[NSMutableArray alloc] init];
[barcodeItems addObjectsFromArray:barcodes];
[barcodeItems addObject:#"test"];
[barcodeItems addObject:#"test1"];
NSLog(#"%#", barcodes);
NSLog(#"%#", barcodeItems);
NSMutableArray<NSIndexPath *>* indexPaths = [[NSMutableArray alloc] init];
for (i = 0; i < barcodeItems.count; i++) {
[indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
[photoCaptureView.itemsTableView insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationAutomatic];
}
And numberOfRowsInSection must return
return barcodeItems.count;

UITableView reloadData with empty array

I am deleting all the items in UITableView. And thus the array from which I am loading the UITableView has count = 0. After deleting the last item in array, on reloading the table, I am getting error at numberofRowInSection.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrProjects count];
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"");
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[tableProject beginUpdates];
Project *project = [arrProjects objectAtIndex:indexPath.row];
[[CommonModel shared]DeleteProjectDetails:project.ProjectId];
[arrProjects removeObject:project];
[self reloadTableProject:YES];
[tableProject endUpdates];
}
}
-(void) reloadTableProject:(BOOL)isReloadRequired
{
//[arrProjects removeAllObjects];
arrProjects = [[CommonModel shared]GetAllProjects];
if(isReloadRequired)
[tableProject reloadData];
}
This is the error :
'Invalid update: invalid number of rows in section 0. The number of
rows contained in an existing section after the update (1) must be
equal to the number of rows contained in that section before the
update (2), plus or minus the number of rows inserted or deleted from
that section (0 inserted, 0 deleted) and plus or minus the number of
rows moved into or out of that section (0 moved in, 0 moved out).'
I am getting this error every time, not only when the array is empty.
Set :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [_datasourceArray count];
}
To empty your TableView, do :
[_datasourceArray removeAllObjects];
[_tableView reloadData];
You need to remove the object from arrProjects too, inside UITableViewCellEditingStyleDelete,
[arrProjects removeObjectAtIndex:indexPath.row];
it is also good to include
[self.tableView beginUpdates] and [self.tableView endUpdates]
when you start and end the removal of these objects
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrProjects count];
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"");
if (editingStyle == UITableViewCellEditingStyleDelete)
{
Project *project = [arrProjects objectAtIndex:indexPath.row];
[[CommonModel shared]DeleteProjectDetails:project.ProjectId];
[arrProjects removeObject:project.ProjectId];
[self reloadTableProject: YES];
}
}

Why am I getting an assert Error When trying to Delete a section in a tableview ios

I have a tableView with some sections, which all have a footer, and then I have a tableViewFooter on the Tableview itself.
If I scroll down to the bottom of my tableview and delete the last item(therefore deleting the section altogether) in any sections above the last section (second last and up) it gives me this error
2014-02-21 13:19:55.066 xxxx[5436:60b] *** Assertion failure in -[UIViewAnimation initWithView:indexPath:endRect:endAlpha:startFraction:endFraction:curve:animateFromCurrentPosition:shouldDeleteAfterAnimation:editing:], /SourceCache/UIKit/UIKit-2903.23/UITableViewSupport.m:2661
Uncaught exception: Cell animation stop fraction must be greater than start fraction
at endUpdates
this is my code
[self.tableView beginUpdates];
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
if(indexPath != nil){
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
NSMutableDictionary *dic =[sec.items objectAtIndex:indexPath.row];
Product* product = [dic valueForKey:PRODUCT];
//removing the item in the section
[sec.items removeObject:dic];
//deleting item from products
NSMutableArray *temp = [NSMutableArray array];
for (Product *p in self.dataCon.listPersister.products) {
if ([p.product.objId isEqualToString: product.product.objId]) {
[temp addObject:p];
}
}
for (Product *p in temp) {
[self.dataCon.listPersister.products removeObject:p];
}
//if it was the last object in section, delete the section else just delete the single row
if(sec.items.count == 0)
{
[self.sections removeObject:sec];
[self.footers removeObjectAtIndex:indexPath.section];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:indexPath.section] withRowAnimation:UITableViewRowAnimationFade];
} else
{
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
USFooterView *footer = [self.footers objectAtIndex:indexPath.section];
footer.totalLabel.text = [self.dataCon.listPersister getTotalForShopId:sec.title];
self.footerView.totalLabel.text = [self.dataCon.listPersister getTotalForAllProducts];
}
}
[self.tableView endUpdates];
I had the same code earlier, just without my tableView and table sections having footers, where it worked, so I think they might be the problem, but I'm not entirely sure that's the reason it's acting up.
I have seen this post
UITableView tableFooterView may cause crash?
And the post that it links to, but that didn't help me.
Any help is appreciated :)
In the else statement you delete row from table view:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
But not from data source. Delete row from array which you use as data source and it should works.
I found a "fix", but I'm avoiding the use of sectionFooter, because that seems to be bugged.
I created an extra cell at the end of each section, with the same setup I had for my footer View before, and made that last cell not editable with
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (sec.items.count != indexPath.row) {
return YES;
} else
return NO;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [sec.items count] +1 ;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"normalcell";
static NSString *CellIdentifier1 = #"footercell";
TableSection * sec = [self.sections objectAtIndex:indexPath.section];
if (indexPath.row != sec.items.count) {
//use normal type of cell
return cell;
} else{
//use footer type of cell
return cell;
}
}
So the last cell Imitates a "footer", but it's not stuck to the bottom of the frame, but I'll have to live with that. It's better than crashes.
Try using UITableViewRowAnimationLeft or UITableViewRowAnimationRight as the delete row animation(deleteRowsAtIndexPaths:withRowAnimation:).
It crashed for me when using UITableViewRowAnimationAutomatic, but not with the other two. I have not tried all of them but it seems to be a bug with the animation code for some of the options.

Assertion failure when updating tableView

Note: when I tap the row, then the app crashes.
I'm trying to implement adding a new cell on a user's tap. I found that there was a similar example in WWDC 2011's table view demonstration. Here's my code from my table view.
Here is the error:
2013-03-19 20:04:28.672 Project[51229:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
Here is my code from the table view.
#interface MyPFQueryTableViewController : PFQueryTableViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
#property (nonatomic, strong) NSIndexPath *controlRowIndexPath;
#property (nonatomic, strong) NSIndexPath *tappedIndexPath;
#implementation MyPFQueryTableViewController {
ListItemObject *listDetail;
}
#synthesize controlRowIndexPath;
#synthesize tappedIndexPath;
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
PFObject *object = [self.objects objectAtIndex:indexPath.row];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[self loadObjects];
}];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"listCell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"listCell"];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.textLabel.text = [object objectForKey:self.textKey];
//cell.imageView.file = [object objectForKey:self.imageKey];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
//if user tapped the same row twice let's start getting rid of the control cell
if([indexPath isEqual:self.tappedIndexPath]){
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
//update the indexpath if needed... I explain this below
indexPath = [self modelIndexPathforIndexPath:indexPath];
//pointer to delete the control cell
NSIndexPath *indexPathToDelete = self.controlRowIndexPath;
//if in fact I tapped the same row twice lets clear our tapping trackers
if([indexPath isEqual:self.tappedIndexPath]){
self.tappedIndexPath = nil;
self.controlRowIndexPath = nil;
}
//otherwise let's update them appropriately
else{
self.tappedIndexPath = indexPath; //the row the user just tapped.
//Now I set the location of where I need to add the dummy cell
self.controlRowIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
}
//all logic is done, lets start updating the table
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath isEqual:self.controlRowIndexPath]){
return 45; //height for control cell
}
return 70; //height for every other cell
}
- (NSIndexPath *)modelIndexPathforIndexPath:(NSIndexPath *)indexPath
{
int whereIsTheControlRow = self.controlRowIndexPath.row;
if(self.controlRowIndexPath != nil && indexPath.row > whereIsTheControlRow)
return [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];
return indexPath;
}
#end
The problem is in your didSelectRowAtIndexPath method. You have:
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
Before you make any calls to tell the table to add or remove any rows, you must update your data source with by adding or removing data. The table will check how many sections and rows there are before and after your add/remove rows. The number of sections and rows after the change must properly reflect how much data you add/remove with how many rows you add/remove.
And of course you must implement the numberOfRowsInSection method.
What does your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section look like?
This error happens when you try to add or delete a row from the UITableView, but the number of rows that you claim to be in the section after the update in that method is not consistent with the new data that should be loaded.
Ex, if your numberOfRowsInSection always returns 4 and you add a row in that section, the tableView will want it to be 5, but it will not be so it will crash. You need to keep track of how many rows are in each section and return that number.

Resources