Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data's NSPrivateQueueConcurrencyType and sharing objects between threads

iOS 5 introduced a new way to quickly fetch data on a background thread by initializing the MOC using NSPrivateQueueConcurrencyType and then doing the fetch in performBlock:

One of the rules of thumb of Core Data has been that you can not share a managed object between threads/queues. Is it still the case with performBlock:? Is the following:

[context performBlock:^{     // fetch request code      NSArray *results = [context executeFetchRequest:request error:nil];      dispatch_async(dispatch_get_main_queue(), ^(void) {         Class *firstObject = [results objectAtIndex:0];         // do something with firstObject     }); }]; 

still unacceptable since I'm sharing my results array/objects between the bg queue and the main queue? Do I still need to use the managed object IDs to do that?

like image 656
samvermette Avatar asked Dec 26 '11 17:12

samvermette


1 Answers

When you use NSPrivateQueueConcurrencyType you need to do anything that touches that context or any object belonging to that context inside the -performBlock: method.

Your code above is illegal since you're passing those objects back to the main queue. The new API helps you in solving this, though: You create one context that's associated with the main queue, i.e. with NSMainQueueConcurrencyType:

// Assume we have these two context (They need to be set up. Assume they are.) NSManagedObjectContext *mainMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType] autorelease]; NSManagedObjectContext *backgroundMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType] autorelease];  // Now this can safely be called from ANY thread: [backgroundMOC performBlock:^{     NSArray *results = [backgroundMOC executeFetchRequest:request error:nil];     for (NSManagedObject *mo in results) {         NSManagedObjectID *moid = [mo objectID];         [mainMOC performBlock:^{             NSManagedObject *mainMO = [mainMOC objectWithID:moid];             // Do stuff with 'mainMO'. Be careful NOT to use 'mo'.         }];     } }]; 

This gets less confusing if you move the inner [mainMOC performBlock:] call into its own method. You may also want to pass an array of object IDs back to the main thread's context in stead of executing a block for each object ID. It depends on your needs.

like image 137
Daniel Eggert Avatar answered Sep 21 '22 04:09

Daniel Eggert