NSFetchedResultsControllerDelegate not firing

2020-07-23 06:33发布

问题:

I can't figure out why, for the life of me, the NSFetchedResultsControllerDelegate methods are not firing when I add data to the underlying datastore. The data shows up immediately if I restart the iPhone application.

I have subclassed UITableViewController and conform to NSFetchedResultsControllerDelegate:

@interface ProjectListViewController : UITableViewController <NSFetchedResultsControllerDelegate> {
    NSFetchedResultsController* fetchedResultsController_;
    NSManagedObjectContext* managedObjectContext_;
}

I instantiate the NSFetchedResultsController and set the delegate to self:

// Controller
fetchedResultsController_ = [[NSFetchedResultsController alloc] initWithFetchRequest:request
    managedObjectContext:self.managedObjectContext 
                                                                  sectionNameKeyPath:@"Client" 
                                                                           cacheName:@"ProjectsCache"];
fetchedResultsController_.delegate = self;

I implement the delegate methods:

- (void)controllerWillChangeContent:(NSFetchedResultsController*)controller {
    NSLog(@"ProjectListViewController.controllerWillChangeContent");
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller { ... }
- (void)controller:(NSFetchedResultsController*)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath { ... }
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id<NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { ... }

I create the entity I wish to save:

Project* newProject = [NSEntityDescription insertNewObjectForEntityForName:@"Project" inManagedObjectContext:self.managedObjectContext];
ProjectDetailViewController* detail = [[ProjectDetailViewController alloc] initWithStyle:UITableViewStyleGrouped 
                                                                                delegate:self 
                                                                                selector:@selector(finishedAdding:) 
                                                                                 project:newProject];

And later, I save it:

- (void)save {
    // NSLog(@"ProjectDetailViewController.save");
    self.project.name = projectNameTextField_.text; 
    NSError* error;
    BOOL b = [self.project.managedObjectContext save:&error];
    if (!b) {
        NSLog(@"Error saving project!");
    } else {
        NSLog(@"Project was successfully saved.");
        [delegate_ performSelector:selector_ withObject:self.project];
    }
    [self dismissModalViewControllerAnimated:YES];
}

It all works just fine except for the fact that my delegate methods don't fire. Obviously my table view doesn't get updated and the only way to see the new data is to explicitly refresh or restart the app.

I've looked through the CoreData Recipe app - but can't seem to find what I'm missing. Thoughts?

-Luther

回答1:

If I change the sectionNameKeyPath from @"Client" to nil when I create the original fetchedResultsController_, both the Project entity creation and save indeed invoke the delegate methods!

fetchedResultsController_ = 
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                        managedObjectContext:self.managedObjectContext 
                                          sectionNameKeyPath:nil
                                                   cacheName:@"ProjectsCache"];

Upon hyper scrutiny, that is what the CoreData Recipes example does. As my data gets more complex - I think I'm going to need that argument to help break the results up into sections but for now, it is nice to see the delegate handlers being invoked.



回答2:

My read of the above looks like you are using 2 NSManagedObjectContexts, one in ProjectListViewController, and seperate one in ProjectDetailViewController (I assume it is created there since I don't see it passed in.

When you save one context it does not automatically propagate changes into another, so saving the one in ProjectDetailViewController will not cause the changes to appear in the context of ProjectListViewController, which means there are no changes in that one to tell the delegate about it.

If you want to push the changes between contexts, look at NSManagedObjectContextDidSaveNotification and mergeChangesFromContextDidSaveNotification: (they are the end of the NSManagedObjectContext documentation).