1

I feel like I've read every CoreData question on Stack Overflow today, and am still very very stuck. :)

I'm working on a application that uses CoreData that is based on the methods illustrated in the Stanford University cs193p Lecture 14 (the Photomania app). It uses a UITableViewController subclass that implements the NSFetchedResultsController delegates, and of course the table updates automatically as results are fetched.

Everything works but the UI blocks when the Document is populated with data, because it occurs in the Main thread (which is the document's managedObjectContext). I'm already downloading the data in a background thread, this is just the code that actually populates the NSManagedObjects that is causing the blocking. The lecture alludes to using the NSManagedObjectContext's Parent context in order to load up the Document in the background and then "refetch" the data in the main thread to populate the table. I almost have things working (I think) except I often get double entries in my table. It seems like the sort of thing [self.tableView beginUpdates] / [self.tableView endUpdates] would resolve, but because I'm doing the NSManagedObjectContext save in the background context I don't know where I would put it.

I may also be going about this the entirely wrong way. :) In any event, here is the relevant code:

NSManagedObjectContext *backgroundContext;
backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// document is my UIManagedDocument
backgroundContext.parentContext = document.managedObjectContext; 

[backgroundContext performBlockAndWait:^{             
     // Do stuff here to populate the document.             
     [backgroundContext save:nil];
}];
stdout
  • 1,761
  • 1
  • 18
  • 33

3 Answers3

1

It's still waiting because you are telling it to do so. Use performBlock, so it can work on its own thread.

[backgroundContext preformBlock:^{
    // Do your background stuff
    [backgroundContext save:&error];  // handle the error
    [document.managedObjectContext performBlock:^{
        // Tell the document it has dirty data and should save
        [document updateChangeCount:UIDocumentChangeDone];
        // Do any UI-related stuff
    }];
}];

The fetched results controller will automatically update when the changes are pushed up into the main context.

Jody Hagins
  • 27,943
  • 6
  • 58
  • 87
0

From your code I can’t see well where the problem might really be. You didn’t make very clear what that “Document” thing is, that you are loading. Anyway, what may help you: try the whole loading in the background thread (that you have), post a notification to let the table view controller know about updates and then just message the controller like:

[self.tableView reloadData];

Then you wouldn’t need beginUpdates nor endUpdates, but if you find a way you need to use them (usually the delegate methods of NSFetchedResultsController use it in -(void)controllerWillChangeContent:(NSFetchedResultsController *)controller and - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller), then send these messages right before updating the data and after doing so.

Hope that helps a bit…

themarketka
  • 672
  • 6
  • 14
  • By the way, as far as I know, NSFetchedResultsController listens for notifications from Core Data, not sure though if from every… – themarketka May 18 '12 at 21:44
  • Thanks, but after trying both your and Jody's suggestions and seeing no change I decided to check the document, and it turns out when I see double entries on screen there really are double entries in the document. So this is a Core Data issue and not just a UI glitch. – stdout May 19 '12 at 12:49
  • It's almost as if [backgroundContext save] is sometimes adding to the Document in the parent context instead of replacing it for some reason. Save never reports an error. The document is a UIManagedDocument that I create earlier in my controller. – stdout May 19 '12 at 13:03
0

Well, not sure why, but this resolved my issue: https://stackoverflow.com/a/9451450/314051. Specifically, right before the [backgroundContext save]:

NSSet *inserts = [backgroundContext insertedObjects]; 
[backgroundContext obtainPermanentIDsForObjects:[inserts allObjects] error:&error]; 

I'll need to do some research to understand exactly why. Thanks for the suggestions, which helped me determine this wasn't a UI issue.

Community
  • 1
  • 1
stdout
  • 1,761
  • 1
  • 18
  • 33