Invalid update: invalid number of rows in section

43,859

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];
Share:
43,859
Admin
Author by

Admin

Updated on December 28, 2020

Comments

  • Admin
    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
    Ashok Londhe about 9 years
    @TapasPal it doesn't matter. And there is some difference between both answer. check it first
  • Sanjay Mohnani
    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
    Tapas Pal about 9 years
    In this scenario there is no need to call reloadData if we use deleteRowsAtIndexPaths
  • Sanjay Mohnani
    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
    Josh about 8 years
    Lol @TapasPal he stole your answer and even got more upvotes than you XD