1
votes

My approach so far has been something like this:

  • 1- A main context initialized like so:

    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
    if(![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
        DDLogModel(@"Unresolved error %@", error.localizedDescription);
        return;
    }
    
    self.context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.context.persistentStoreCoordinator =_persistentStoreCoordinator;
    
  • 2- Then, as I go about creating core data objects or modifying their relationships concurrently:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSManagedObjectContext *tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    tempContext.persistentStoreCoordinator = self.persistentStoreCoordinator;
    
    //  Do stuff
    
    [tempContext save:nil];
    });
    
  • 3- And finally, the main context merge via the NSManagedObjectContextDidSaveNotification

However, I've recently seen a different approach where for step 2, they instead create a context with NSPrivateQueueConcurrencyType, make it a child of the main context, and do any work by means of -performBlock:

Is this last approach concurrent by default (even without explicitly dispatching it as such)? Or what's the advantage over the approach I explained?

Another thing that threw me off is that even though the contexts have parentContext and persistentStoreCoordinator properties, it appears that setting the latter implies one cannot set the former. That is, a context with a persistent store coordinator actually has that store coordinator as it's parent context?

UPDATE: Another interesting thing is that with the approach I described above (using GCD), everynow and then when I do [tempContext save:] I get a weird behaviour: No error is returned (assuming I do pass in an NSError object, unlike in the example), but if I set the generic Objective-C exception pointer on, the background thread does stop there, as if there was an exception. However, if I continue the app does not crash and keeps going and the main moc seems to be just fine.

1

1 Answers

0
votes

You are right. performBlock will automatically perform the work in the background. In some cases it might make sense to use the current thread (main or background), in which case you can use performBlockAndWait. Using child contexts is the recommended approach.

I suppose your setup could work just as well. I guess the advantage of using a child context lies in a more structured approach of saving, i.e. "pushing up" saves into the parent context. Only the parent context will actually touch the persistent store, so this is better in terms of thread safety.

Your last question is not clear. A context can only have a context as its parent context, not a persistent store coordinator. However, what might be confusing you is that prior to iOS 5 there was only a "Parent Store", and with the introduction of child contexts it could be replaced optionally by a parent context. Read all about it here.