Animating Row Deletion in UITableView with CoreData gives Assertion failure

16,586

Solution 1

1) I set up a correct delegate.

2) I removed a call in viewWillLoad to [self.tableview reloadData]; which was (oddly) messing everything up (this post gave me a clue for what to look for and remove: Serious Application Error in Core Data with fetchedResultsContainer ).

Solution 2

When we use NSFetchedResultsController as DataSource of UITableView, we can't invokedeleteRowsAtIndexPaths: withRowAnimation: in function tableView: commitEditingStyle: forRowAtIndexPath:, which will throw exception as question mentioned.

One way to solve this issue is by invoking [self.tableView reloadData] in controllerDidChangeContent: from protocol NSFetchedResultsControllerDelegate. It actually solves, however, there is not Delete Fade Animation anymore.

So, the alternative convenient way is by invoking [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade] in controller: didChangeObject: atIndexPath: forChangeType: newIndexPath:.

Sample code as below:


- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
   forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Delete NSManagedObject
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    [context deleteObject:object];

    // Save
    NSError *error;
    if ([context save:&error] == NO) {
        // Handle Error.
    }
}

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject 
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type 
      newIndexPath:(NSIndexPath *)newIndexPath
{
    if (type == NSFetchedResultsChangeDelete) {
        // Delete row from tableView.
        [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                              withRowAnimation:UITableViewRowAnimationFade];
    }
}
Share:
16,586
glenstorey
Author by

glenstorey

We have released BookBot, Silent Light, Math Shake and Times Table Galaxy for iOS and Purrfect Memory of OSX - http://topstoreyapps.com ICT Infrastructure lead for innovative Apple Distinguished School in Papamoa, New Zealand.  ADE Class of 2015.

Updated on June 04, 2022

Comments

  • glenstorey
    glenstorey almost 2 years

    I have a UITableView that shows a list of objects stored with CoreData. I can delete an object using the following code:

    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        NSLog(@"Delete row");
        [managedObjectContext deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
    
        // Save the context.
        NSError *error;
        if (![managedObjectContext save:&error]) {
            /*do this gracefully one day */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        }
        [self refreshTables]; //where refreshTables just reloads the data the table is using and calls [self.tableView reloadData];
    }
    
    }
    

    But it has no animation or aesthetic.

    When I try to animate by replacing

    [self refreshTables]; 
    

    with

    [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    

    I get the following error:

    Assertion failure in -[UITableView _endCellAnimationsWithContext:], >/SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:920 2010-10-30 16:46:35.717 MyApp[38226:207] * 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 (3) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted).'

    I've tried having the deleteRowsAtIndexPaths code in a variety of places in the commitEditingStyle code with no luck (for example before removing the object from the mOC) but I can't seem to get around this error.

    I know Apple's iPhoneCoreDataRecipes example handles the problem by setting up a delegate for the FetchedResultsController to handle editing / deleting rows, but at this stage in development, if possible, I just want a simple solution for animating those deleted objects.

    How can I animate the removal of a row, before/after I remove the object from my managedObjectContext?

    EDIT: I've tried having deleteRowsAtIndexPaths before and after removing the item from the mOC, with the same error.

  • glenstorey
    glenstorey over 13 years
    No, that doesn't work. I did try that before posting. Same error: Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-1261.5/UITableView.m:92
  • glenstorey
    glenstorey over 13 years
    I am using NSFetchedResultsController and a core data source with no problems. The sans-animation code successfully removes the coredata object. It's only the animation that is causing trouble.
  • Matthias Bauch
    Matthias Bauch over 13 years
    @glenstorey I guess I didn't read your question thoroughly the first time, see my edit.
  • seanicus
    seanicus over 11 years
    This worked for me... great answer to a frustrating "late in the evening" sort of problem!