简体   繁体   中英

Can I use MOC's performBlock: inside an NSOperation subclass?

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, ie 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?

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...

  • The code is probably safe depending on what your other operations do.
  • Since 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM