Isti Isti - 3 months ago 14
iOS Question

How to remove an object from data array (core data)

I have a table view with sections. when I try to delete a row from the table view i get the following error.........

'Invalid update: invalid number of rows in section 5. The number of rows contained in an existing section after the update (4) must be equal to the number of rows contained in that section before the update (4), 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).'

After some online research I understand that I have to remove the object from the array.
I am using core data with standard managedObjectContext and fetchedResultsController. I don't understand what is the array here.
Can someone help please.

Here is the code for number of section and number of rows....

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = [[self.fetchedResultsController sections] count];
return count;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];

NSInteger count = [sectionInfo numberOfObjects];
return count;
}


Below is the code I am using to delete a row....

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {

// Delete the managed object at the given index path.
NSManagedObject *birthdayToDelete = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:birthdayToDelete];

// Update the array and table view.
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:YES];

// Commit the change.
NSError *error = nil;
if (![self.managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}

[_birthdayTableView reloadData];
}

Answer

You don't need to call [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:YES]; if you are using NSFetchResultsController delegate methods. Implement the following: These will get called after you save your managedObjectContext post deletion. (remember to set the delegate of your NSFetchedResultsController. Also, DONT call [tableView reloadData];. It will make the animation skip and look weird :-) This is the beauty of using NSFetchedResultsController, it does the heavy lifting for you and listens out for changes on the managedObjectContext

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
    [tableView beginUpdates];
}

- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
       switch(type) {
         case NSFetchedResultsChangeInsert:
             [tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                      withRowAnimation:UITableViewRowAnimationRight];
        break;

        case NSFetchedResultsChangeDelete:
             [tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                      withRowAnimation:UITableViewRowAnimationLeft];
            break;
        case NSFetchedResultsChangeMove:break;
        case NSFetchedResultsChangeUpdate:break;
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath
{
     switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationLeft];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
            break;

        case NSFetchedResultsChangeUpdate:
            [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
     [tableView endUpdates];
}