Reputation: 1789
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];
}];
Upvotes: 1
Views: 1359
Reputation: 1789
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.
Upvotes: 0
Reputation: 28419
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.
Upvotes: 1
Reputation: 712
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…
Upvotes: 0