Invalid update: invalid number of rows in section
Solution 1
In - (void)swipeableTableViewCell: didTriggerRightUtilityButtonWithIndex:
You need to remove either
[self.medicationsTableView reloadData];
or
[self.medicationsTableView deleteRowsAtIndexPaths:@[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
Because on first line when reloadData
get called it's reload the tableview with new datasource and again calling deleteRowsAtIndexPaths
tried to delete a rows which already removed by calling reloadData
earlier.
Solution 2
The important thing is that you need to use either
[self.medicationsTableView reloadData];
or
[self.medicationsTableView deleteRowsAtIndexPaths:@[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
The reason being, when the tableview's reload data
is called the row which is removed from data source is deleted and after that when the delete row api is called for the same index path
(where the row is already deleted causes the issue)
Also just before deleting the row from the table delete the object from the data source (self.fetchedResultsController1
) and call
[self.medicationsTableView deleteRowsAtIndexPaths:@[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight];
and after the above row's deletion animation is completed than you can call(but it is not required)
[self.medicationsTableView reloadData];
Admin
Updated on December 28, 2020Comments
-
Admin over 3 years
I am working on a project using
Microsoft Azure services
. In that while deleting a row I am getting this error:Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) 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, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
Code for table load and delete row is as :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 3; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //medicine list if (section == 0) { NSArray *sectionInfo = [self.fetchedResultsController1 fetchedObjects]; return [sectionInfo count]; } //allergy list else if (section == 1) { NSArray *sectionInfo = [self.fetchedResultsController2 fetchedObjects]; return [sectionInfo count]; } //notes list else if (section == 2){ NSArray *sectionInfo = [self.fetchedResultsController3 fetchedObjects]; return [sectionInfo count]; } else return 0; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *cellIdentifier = @"mcell"; MedicationTableViewCell *cell = (MedicationTableViewCell *) [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; // Add utility buttons NSMutableArray *rightUtilityButtons = [NSMutableArray new]; [rightUtilityButtons sw_addUtilityButtonWithColor: [UIColor colorWithRed:1.0f green:0.231f blue:0.188 alpha:1.0f] title:@"Delete"]; switch (indexPath.section) { case 0: { NSManagedObject *item = [self.fetchedResultsController1 objectAtIndexPath:indexPath]; cell.textLabel.text = [item valueForKey:@"name"]; break; } case 1: { NSManagedObject *item = [self.fetchedResultsController2 objectAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row inSection:0]]; cell.textLabel.text = [item valueForKey:@"name"]; break; } case 2: { NSManagedObject *item = [self.fetchedResultsController3 objectAtIndexPath: [NSIndexPath indexPathForRow:indexPath.row inSection:0]]; cell.textLabel.text = [item valueForKey:@"title"]; break; } default: break; } cell.rightUtilityButtons = rightUtilityButtons; cell.delegate = self; return cell; } - (void)swipeableTableViewCell:(SWTableViewCell *)cell didTriggerRightUtilityButtonWithIndex:(NSInteger)index { // Delete button is pressed NSIndexPath *cellIndexPath = [self.medicationsTableView indexPathForCell:cell]; //fetchingg data from local store first NSManagedObject *item = [self.fetchedResultsController1 objectAtIndexPath:[NSIndexPath indexPathForRow:cellIndexPath.row inSection:0]]; NSMutableArray *keys = [[NSMutableArray alloc] initWithObjects:@"id", @"name", @"userId", nil]; NSMutableArray *values = [[NSMutableArray alloc] initWithObjects: [item valueForKey:@"id"], [item valueForKey:@"name"], [item valueForKey:@"userId"], nil]; //creating dictionary of data NSDictionary *dict = [[NSDictionary alloc] initWithObjects:values forKeys:keys]; //calling delete fucntion [self.authService deleteItem:self.syncTable withDict:dict completion:^{ //removing row from table view [self.medicationsTableView reloadData]; [self.medicationsTableView deleteRowsAtIndexPaths:@[cellIndexPath] withRowAnimation:UITableViewRowAnimationRight]; }]; break; }
Please tell where I am going wrong. Thanks in advcance!!!!
-
Ashok Londhe about 9 years@TapasPal it doesn't matter. And there is some difference between both answer. check it first
-
Sanjay Mohnani about 9 years@TapasPal, it could happen that a person while creating answer do not see the answers that were posted while he/she was in the process of creating answer and most importantly why should he care about the other persons post whether their answers are matching with mine or like so?
-
Tapas Pal about 9 yearsIn this scenario there is no need to call
reloadData
if we usedeleteRowsAtIndexPaths
-
Sanjay Mohnani about 9 years@Tapas Pal, yes you are absolutely right, and that's what I also mentioned in my answer as well (see the last couple of lines of my answer)
-
Josh about 8 yearsLol @TapasPal he stole your answer and even got more upvotes than you XD