Reputation: 2618
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
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
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