Search code examples
ioscore-dataconcurrencynsmanagedobjectcontext

Unable to set a context in a private queue as child of another context in main queue


As far as I understood, it is possible to create an NSManagedObjectContext in a private queue and set its parent context to be another NSManagedObjectContext that belongs to main thread... isn't it?

I'm trying to do this:

NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainContext = appDelegate.managedObjectContext;
[privateContext setParentContext:mainContext]; 

But I get a SIGABRT error at [privateContext setParentContext:mainContext] when I run this code.

The mainContext I retrieve from AppDelegate is initialized in main thread, and this code snippet is also called in main thread. What could I doing wrong or missing?

Thanks

EDIT: If I instead do this (in AppDelegate):

NSManagedObjectContext *mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
mainContext.persistentStoreCoordinator = self.managedObjectContext.persistentStoreCoordinator;
NSManagedObjectContext *privateContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

privateContext.parentContext = mainContext;

I get no error... why could this be happening? What does the default context provided in AppDelegate have that it doesn't work as parent context?

EDIT 2: The context in AppDelegate I'm trying to set as parent context is initialized by using the methods that are provided by default in AppDelegate:

- (NSManagedObjectContext *)managedObjectContext
{
   // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
   if (_managedObjectContext != nil) {
       return _managedObjectContext;
   }

   NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
   if (!coordinator) {
       return nil;
   }
   _managedObjectContext = [[NSManagedObjectContext alloc] init];
   [_managedObjectContext setPersistentStoreCoordinator:coordinator];
   return _managedObjectContext;
}

Solution

  • It's hard to detect what does throw the exception in your case - too less info.

    At a first glance everything seems fine, but - please, mind setting up your parent/child contexts in following order:

    1. Create root context.
    2. Set its persistentStoreCoordinator
    3. Create child context
    4. Set its parentContext to root context
    5. Continue setting up parent/child hierarchy with 3-4

    In your case exception may arise due to:

    1. mainContext is nil
    2. mainContext's persistentStoreCoordinator is nil

    Anyway, the fastest solution will be log exception fired by a CoreData. You may use NSSetUncaughtExceptionHandler

    EDIT 1:

    To ne consistent try to use NSManagedObjectContext *mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; in your initialization method in AppDelegate instead of alloc/init but it's most likely not the fix of the problem. Again, read the exception message in the console - this will give an exact idea what's going wrong.