iOS Developer Library


Core Data Framework Reference NSFetchedResultsControllerDelegate Protocol Reference

Deployment Target:

On This Page


An instance of NSFetchedResultsController uses methods in this protocol to notify its delegate that the controller’s fetch results have been changed due to an add, remove, move, or update operations.

You should consider carefully whether you want to update the table view as each change is made. If a large number of modifications are made simultaneously—for example, if you are reading data from a background thread—it may be computationally expensive to animate all the changes. Rather than responding to changes individually (as illustrated in Typical Use), you could just implement controllerDidChangeContent: (which is sent to the delegate when all pending changes have been processed) to reload the table view.

The fetched results controller reports changes to its section before changes to the fetched objects themselves.

Typical Use

You can use controllerWillChangeContent: and controllerDidChangeContent: to bracket updates to a table view whose content is provided by the fetched results controller as illustrated in the following example:

  1. /*
  2. Assume self has a property 'tableView' -- as is the case for an instance of a UITableViewController
  3. subclass -- and a method configureCell:atIndexPath: which updates the contents of a given cell
  4. with information from a managed object at the given index path in the fetched results controller.
  5. */
  6. - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
  7. [self.tableView beginUpdates];
  8. }
  9. - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
  10. atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
  11. switch(type) {
  12. case NSFetchedResultsChangeInsert:
  13. [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
  14. withRowAnimation:UITableViewRowAnimationFade];
  15. break;
  16. case NSFetchedResultsChangeDelete:
  17. [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
  18. withRowAnimation:UITableViewRowAnimationFade];
  19. break;
  20. }
  21. }
  22. - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
  23. atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  24. newIndexPath:(NSIndexPath *)newIndexPath {
  25. UITableView *tableView = self.tableView;
  26. switch(type) {
  27. case NSFetchedResultsChangeInsert:
  28. [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
  29. withRowAnimation:UITableViewRowAnimationFade];
  30. break;
  31. case NSFetchedResultsChangeDelete:
  32. [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
  33. withRowAnimation:UITableViewRowAnimationFade];
  34. break;
  35. case NSFetchedResultsChangeUpdate:
  36. [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
  37. atIndexPath:indexPath];
  38. break;
  39. case NSFetchedResultsChangeMove:
  40. [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
  41. withRowAnimation:UITableViewRowAnimationFade];
  42. [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
  43. withRowAnimation:UITableViewRowAnimationFade];
  44. break;
  45. }
  46. }
  47. - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
  48. [self.tableView endUpdates];
  49. }

User-Driven Updates

In general, NSFetchedResultsController is designed to respond to changes at the model layer. If you allow a user to reorder table rows, then your implementation of the delegate methods must take this into account.

Typically, if you allow the user to reorder table rows, your model object has an attribute that specifies its index. When the user moves a row, you update this attribute accordingly. This, however, has the side effect of causing the controller to notice the change, and so inform its delegate of the update (using controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:). If you simply use the implementation of this method shown in Typical Use, then the delegate attempts to update the table view. The table view, however, is already in the appropriate state because of the user’s action.

In general, therefore, if you support user-driven updates, you should set a flag if a move is initiated by the user. In the implementation of your delegate methods, if the flag is set, you bypass main method implementations; for example:

  1. - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
  2. atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  3. newIndexPath:(NSIndexPath *)newIndexPath {
  4. if (!changeIsUserDriven) {
  5. UITableView *tableView = self.tableView;
  6. // Implementation continues...
  • Specify types of change.



    enum NSFetchedResultsChangeType : UInt { case Insert case Delete case Move case Update }


    enum { NSFetchedResultsChangeInsert = 1, NSFetchedResultsChangeDelete = 2, NSFetchedResultsChangeMove = 3, NSFetchedResultsChangeUpdate = 4 }; typedef NSUInteger NSFetchedResultsChangeType;


    • Insert


      Specifies that an object was inserted.

      Available in iOS 3.0 and later.

    • Delete


      Specifies that an object was deleted.

      Available in iOS 3.0 and later.

    • Move


      Specifies that an object was moved.

      Available in iOS 3.0 and later.

    • Update


      Specifies that an object was changed.

      Available in iOS 3.0 and later.

    Import Statement


    @import CoreData;


    import CoreData


    Available in iOS 4.0 and later.