Last Updated: February 25, 2016
·
4.093K
· JuanKaram

Core Data + Gran Central Dispatch

Core Data has a particular strategy to support multi-threading named Use Thread Confinement, this strategy is well explained in the Apple documentation but it reduces to the three following rules:

1.- Have only one NSPersistentStoreCoordinator per app

2.- Create one NSManagedObjectContext per thread

3.- Do not pass NSManagedObject instances between threads

In the following example I am assuming that you create a data model with the object Person:

// Create a new background queue for GCD
dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

// Dispatch the following code on our background queue
dispatch_async(backgroundDispatchQueue,
^{
    // Because at this point we are running in another thread we need to create a
    // new NSManagedContext using the app's persistance store coordinator
    NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
    [backgroundThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];

    // Now we can create a new object using the NSManagedContext of this thread
    Person *backgroundThreadPerson = [NSEntityDescription insertNewObjectForEntityForName:@"Person"
                                                   inManagedObjectContext:backgroundThreadContext];
    backgroundThreadPerson.name = @"Juan";


    // Is very important that you save the context before moving to the Main Thread,
    // because we need that the new object is writted on the database before continuing
    NSError *error;

    if(![backgroundThreadContext save:&error])
    {
      NSLog(@"There was a problem saving the context. With error: %@, and user info: %@",
            [error localizedDescription],
            [error userInfo]);
    }


    // Now let's move to the main thread
    dispatch_async(dispatch_get_main_queue(), ^
    {
      // If you have a main thread context you can use it, this time i will create a
      // new one
      NSManagedObjectContext *mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
      [mainThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];

      NSError *error;

      // Retreive the new person object in the main thread using the Core Data Object ID
      Person *mainThreadPerson = (Person *)[mainThreadContext existingObjectWithID:[backgroundThreadPerson objectID] error:&error];

      // We need to check that the operation was successfull
      if(mainThreadPerson == nil)
      {
        NSLog(@"There was a problem retrieving a Managed Object. With error: %@, and user info: %@",
              [error localizedDescription],
              [error userInfo]);
      }

      // This prints "Juan"
      NSLog(@"%@", mainThreadPerson.name);
    });
});

Prost!

JK