Question

According to KVO observing of NSMangedObject in a UITableViewCell, one should implement NSFetchedResultsControllerDelegate rather than using KVO to observe propery changes on managed objects fetched with NSFetchedResultsController.

But how can I determined which properties have changed and on which objects?

I have data updates streaming in via a socket updating my managed objects, and want my UI to update accordingly whenever certain properties of listed objects change. I don't want to redraw the whole table, or each cell, only the label that displays the value of the property that changed, for example.

Is this doable, or should I resort to KVO but optimize it somehow?

Was it helpful?

Solution

You should not use KVO for updating CoreData objects. The reason being: the same object record can be retrieved from two separate contexts, and KVO observing would only notify you of the object from your view's context, leaving you unaware of updates made on the same object in a different context. Using the delegate methods from the fetched results controller allows you to respond to changes made on an object from other contexts. Here's example code taken from the 'CoreDataBooks' sample project, and is the proper way to respond to changes using a fetched results controller:

/*
 NSFetchedResultsController delegate methods to respond to additions, removals and so on.
 */
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {

    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}


- (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:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            [tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{    
    switch(type) {

        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationAutomatic];
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top