Custom cell on empty table with NSFetchedResultsController

core-data, ios, objective-c, uitableview

Solution

After a table view update, the value returned by `numberOfRowsInSection` must exactly match the previous number of rows plus the number of inserted rows minus the number of deleted rows.

In your case, when the first object is inserted, `insertRowsAtIndexPaths` is called in the FRC delegate method for the new object, but instead of displaying an additional row, the "empty" cell is replaced with a different cell, so the number of rows is still one.

It should work if you modify the FRC delegate method `controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:` as follows:

case NSFetchedResultsChangeInsert:
    if ([[self.fetchedResultsController fetchedObjects] count] == 1) {
        // First object inserted, "empty cell" is replaced by "object cell"
        [tableView reloadRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else {
        [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
    break;

case NSFetchedResultsChangeDelete:
    if ([[self.fetchedResultsController fetchedObjects] count] == 0) {
        // Last object removed, "object cell" is replaced by "empty cell"
        [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else {
        [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    }
    break;

Problem

I'm trying to place a custom empty cell when my UITableView is empty. I use the following code: ``` - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { return 1; } return count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell * cell = nil; int count = [self.fetchedResultsController fetchedObjects].count; if (count == 0) { // return empty cell cell = [self getEmptyCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } else { cell = [self getMyQuestionCellOfTableView:tableView cellForRowAtIndexPath:indexPath]; } return cell; } ``` FRC didChangeObject implementation: ``` - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { if (!self.suspendAutomaticTrackingOfChangesInManagedObjectContext) { switch(type) { case NSFetchedResultsChangeInsert: [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeDelete: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeUpdate: [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; break; case NSFetchedResultsChangeMove: [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade]; break; } } } ``` This works perfectly, the problam is when the fetchedObject.count > 0 than i get the following error: ``` CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to - controllerDidChangeContent: 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 (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). with userInfo (null) ``` I understand that this happens because I inserted 1 new row and the count stays at 1 instead of becoming 2. How can i fix it to fit my behavior?

Original source