The docs for NSFetchedResultsControllerDelegate provide the following sample code
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
When I create a new NSManagedObject, NSFetchedResultsChangeInsert fires (great!). When I change the value of an attribute (used for the cell's title), the NSFetchedResultsChangeUpdate fires. Unfortunately, the new title doesn't automatically display unless I reload the table, section or row. Indeed, if the new name causes the result set to sort differently, then NSFetchedResultsChangeMove fires and all is well since the provided code reloads the entire section.
UITableView has a method reloadRowsAtIndexPaths:withRowAnimation so I tried using this under the NSFetchedResultsChangeUpdate code block. It does indeed work ... but the docs for this specific method read as though I don't need it (notice the last line):
Reloading a row causes the table view to ask its data source for a new cell for that row. The table animates that new cell in as it animates the old row out. Call this method if you want to alert the user that the value of a cell is changing. If, however, notifying the user is not important—that is, you just want to change the value that a cell is displaying—you can get the cell for a particular row and set its new value.
And yes, if I log what is happening, when
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
gets invoked on an NSFetchedResultsChangeUpdate, it is able to retrieve the latest 'name' value and set it in the cell's textLabel. The name is just not rendering in the cell unless I reload it. Even if I simply click the cell the name shows up. Note that to recreate this behavior, you must create a new managed object and then give it a name that causes it to sort FIRST in the NSFetchedResultsController. That way, the NSFetchedResultsChangeMove doesn't fire (which does work since it reloads the section).
Am I missing something or is this expected behavior? The 'discussion' for reloadRowsAtIndexPaths leads me to believe I should be able to simply set the cell's textLabel without reloading the row, section or table.