In my App I am fetching requests with JSON content, parsing them and storing them in CoreData. In the same time the user is interacting with the DB (reading and writing access).
After storing data to the DB a second task is started that create new data, based on the received data. Im going to use Grand Central Dispatch to do the parsing and storing the data to the DB.
My problem is that when using GCD I get a EXC_BAD_ACCESS which could me caused of the non thread safety of Core Data I assume. An other error is that I get a deadlock when using context performBlockAndWait.
How should I design my app that has a proper handling of GCD and NSMutableContexts?
——-EDIT——–
Now that I have read the core data programming guide I cam to the point that I have to use the Thread Confinement Pattern.
My App is currently structured this way: I have a couple of Managers that each hold their own context. But when using several threads I come to the point where 3 threads call the same Manager which means that one context is used by 3 threads simultaneously. This results in a deadlock.
To solve this I came to the idea to create a context by threadname like this:
- (NSManagedObjectContext *)createManagedObjectContextWithTreadName:(NSString*) threadname {
if([NSThread currentThread].name.length ==0){
[NSThread currentThread].name = threadname;
}
NSManagedObjectContext *context = nil;
context = [self.contextStore objectForKey:threadname];
if(!context){
NSLog(@"Creating context for threadname: %@",threadname);
NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
if (coordinator != nil)
{
context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
context.persistentStoreCoordinator = coordinator;
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(mergeChangesFromMOC:) name:NSManagedObjectContextDidSaveNotification object:context];
[self.contextStore setValue:context forKey:threadname];
}
}
return context;
}
Is this a good idea?
Ok – here is how I solved it:
Anywhere I need a context, I ask [ContainingClass managedObjectContext] and get the context for the main thread or the thread I am in. When a merge is needed this is performed on the main thread.