Sagar D
Sagar D

Reputation: 2618

How to handle NSManagedObjectContext and NSManagedObject creation and editing on multiple threads?

I have an application where I’m using Core Data. It’s my first time with it so I’m using the same Core Data stack that Apple provides in the AppDelegate.m .

The problem I’m facing is described below : I have a method called firstSaver which performs operations as :

+(void) firstSaver  {
    // 1) get some values from system
    // 2) do some processing on those values ( This takes considerable time)
    // 3) create a NSManagedObject instance of entity A ,say mObj ,by filling in the processed  values. I create multiple objects. In this step, I use the main managedObjectContext that is provided by the        AppDelegate to me. 
    // 4) pass this NSManagedObject to secondSaver like : 
        [self secondSaver : mObj];
    // 5) save the managedObjectContext.
}

the second method works as :

+(void) secondSaver : (NSManagedObject *)someObj { 

    // 1) again fetch some values, this too takes considerable time.
    // 2) create a NSManagedObject which is instance of entity B, fill the processed values, attach this instance to the someObj instance.
    return;
}

Note that A is related to B by a one-to-many relationship, i.e. A contains a NSSet of B. As seen, the two calls require considerable time to complete and it freezes the UI. I don’t want it to happen hence I created a serial dispatch_queue and called the firstSaver on it using dipatch_async.

The problem is that as the instance of NSManagedObjectContext has been created on the main thread, and if I access it inside dispatch_async, it results in EXEC_BAD_ACCESS.

What could possibly be the correct approach to handle this scenario and use proper managed object context for dealing with multithreading ? Any help will be appreciated.

Upvotes: 1

Views: 192

Answers (2)

Wain
Wain

Reputation: 119041

You should create new child managed object contexts to use, with private queue type and the main context as the parent. All of your logic should be in a performBlockAndWait: and that's where you do your long query and create the new object.

To use the mObj here you need to get its objectID and then use existingObjectWithID:error: to get the appropriate version in the child context. Then you can connect your new object to the existing object but in the correct context.

When you're done, save the child context and then use performBlock on the main context and save it.

// move to background thread
// create child
// set parent
// perform block and wait on new context
  // find the existing object for mObj ID
  // search, create, associate
  // save
  // perform block on the main context
    // save

Upvotes: 4

Thallius
Thallius

Reputation: 2619

Multithreadding with Coredata is a pain in the ass. You should avoid this if possible. If the creation or modification of an MO takes long time, create the data or modify the exiting one in a background thread and then do a performSelectorOnMainthread for all Coredata actions.

Upvotes: -1

Related Questions