Reputation: 964
The docs state that NSManagedObjectContext with NSPrivateQueueConcurrencyType lets the user perform asynchronous code by using performBlock:. But what happens if I want to write an NSOperation subclass for processing managed objects in such a child context/private queue setup?
For example:
// Get managed object IDs from selected objects (defined in one of my own categories).
NSArray * selectedObjIDs = [NSManagedObjectContext IDsWithObjects:self.arrayController.selectedObjects];
NSBlockOperation * operation = [NSBlockOperation blockOperationWithBlock:^
{
NSManagedObjectContext * childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childContext.parentContext = myMainMOC;
[childContext performBlock:^
{
// Get objects in child context with previously generated managed object IDs (again, from my own category).
NSArray * privateObjects = [childContext objectsWithIDs:selectedObjIDs];
// Do something with the objects.
for( NSManagedObject * object in privateObjects )
{
[object setValue:@"New Title" forKey:@"title"];
}
[childContext save:NULL];
}];
}];
// Execute in our own private NSOperationQueue.
[self.backgroundQueue addOperation:operation];
The code works fine but when setting breakpoints inside both blocks I can see that execution first goes into background thread A (spawned by NSBlockOperation), then into background thread B (dedicated to the child MOC - as expected.
(BTW: I believe I saw an equivalent setup in the sample code of Apple's WWDC session "Advanced NSOperations".)
Question #1: are these two nested dispatches a problem somehow, i.e. in terms of performance? It just doesn't seem right to me - shouldn't the code run in the child MOC's private queue only?
Question #2: imagine I would subclass NSOperation (instead of using NSBlockOperation). Should I override its 'asynchronous' property to return YES to really just use the child MOC's private queue?
Upvotes: 0
Views: 178
Reputation: 70966
Your code isn't exactly wrong but it's more complicated than it needs to be.
When you call performBlock
, you are telling the managed object context to execute the block asynchronously on a private queue. That block is already asynchronous with regard to the code that calls performBlock
. Wrapping it in an NSOperation
is probably safe but also completely unnecessary. As soon as your code calls performBlock
, the NSOperation
will complete, because of the asynchronous nature of performBlock
. In short, the NSOperation
is completely unnecessary here.
You could replace performBlock
with performBlockAndWait
, but that wouldn't make a lot of sense. You'd be forcing the NSOperation
to wait, but for no good reason.
Subclassing NSOperation
as you mention is also unnecessary unless you have some other asynchronous requirement that you didn't mention. How to configure the NSOperation
is irrelevant-- just get rid of it.
Update since in a comment it seems you do have other async requirements...
performBlock
returns immediately, the next operation in the queue will run in parallel with this one on a different queue. Does that matter? It depends what other operations in the queue are doing. If they depend on this performBlock
having finished, that's a problem. You could deal with this using performBlockAndWait
to keep the queue serial.Upvotes: 0