Core Data background fetching via new NSPrivateQueueConcurrencyType

Core DataIos5

Core Data Problem Overview


Is it really so simple now in iOS5?

I used to perform a background fetch using this code in my AppDelegate:

dispatch_queue_t downloadQueue = dispatch_queue_create("DownloadQueue", NULL);
dispatch_async(downloadQueue, ^{
        self.myDownloadClass = [[MyDownloadClass alloc]initInManagedObjectContext:self.managedObjectContext];
        [self.myDownloadClass download];
    });
    
dispatch_release(downloadQueue);

My download class performs an NSURLConnection to fetch some XML data, uses NSXMLParser to parse the data, and then updates a complex schema in core data. I would always switch to the main thread to actually update the core data. Messy code, with lots of calls to dispatch_sync(dispatch_get_main_queue()....

My new code looks like this:

NSManagedObjectContext *child = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[child setParentContext:self.managedObjectContext];

[child performBlock:^{
	self.myDownloadClass = [[MyDownloadClass alloc]initInManagedObjectContext:child];
	[self.myDownloadClass download];
	}];

along with a small change to some other code in my AppDelegate to set the parent model object context type to NSMainQueueConcurrencyType:

- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil)
    {
        return __managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
        __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}

It seems to work very well. The entire update process still runs in a separate thread, but I did not have to create a thread. Seems like magic.

Just remember if you want to commit your changes to the physical core data files, you have call save: on the parent context as well.

I didn't really ask a question here. I'm posting this so it helps others because everything I found when searching for the new iOS5 managed object context methods only gave high level details with no code examples And all the other searches for fetching core data in the background are old, sometimes very old, and discuss how to do it pre-iOS5.

Core Data Solutions


Solution 1 - Core Data

Yes - it is really that easy now (in iOS 5.0). For iOS 4 compatibility, the previous hurdles remain, but the documentation is not too bad on thread confinement. Maybe you should add this to a wiki section?

Solution 2 - Core Data

I'm trying to understand how this new API is implemented. My usual pattern for multithreaded core data is something like this:

Usually in a NSOperation but simplified using dispatch_async in this example:

dispatch_queue_t coredata_queue; // some static queue

dispatch_async(coredata_queue, ^() {
    // get a new context for this thread, based on common persistent coordinator
    NSManagedObjectContext *context = [[MyModelSingleton model] threadedContext];
    
    // do something expensive
    
    NSError *error = nil;
    BOOL success = [context save:&error];
    if (!success) {
        // the usual.
    }
    
    // callback on mainthread using dispatch_get_main_queue();
});

Then the main thread will respond by updating the UI based on NSManagedObjectContextDidSaveNotification to merge the main context.

The new API's seem to be a wrapper around this pattern, where the child context looks like it just takes the persistent coordinator from its parent to create a new context. And specifying NSPrivateQueueConcurrencyType on init will make sure the performBlock parameter is executed on the private queue.

The new API doesn't seem to be much less code to type. Any advantages over the 'traditional' threading?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaul HellerView Question on Stackoverflow
Solution 1 - Core DataScott CorscaddenView Answer on Stackoverflow
Solution 2 - Core DataJoris KluiversView Answer on Stackoverflow