我可以在NSOperation子类中使用MOC的performBlock吗?

时间:2018-01-20 10:14:15

标签: ios multithreading macos core-data concurrency

文档声明带有NSPrivateQueueConcurrencyType的NSManagedObjectContext允许用户使用performBlock:执行异步代码。但是,如果我想编写一个NSOperation子类来处理这种子上下文/私有队列设置中的托管对象,会发生什么?

例如:

// 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];

代码工作正常,但在两个块中设置断点时,我可以看到执行首先进入后台线程A(由NSBlockOperation生成),然后进入后台线程B(专用于子MOC - 正如预期的那样。

(顺便说一句:我相信我在Apple的WWDC会话“高级NSOperations”的示例代码中看到了相同的设置。)

问题#1:这两个嵌套的调度是否存在某种问题,即在性能方面?它对我来说似乎不对 - 代码不应该只在子MOC的私有队列中运行吗?

问题#2:想象一下我会继承NSOperation(而不是使用NSBlockOperation)。我是否应该覆盖其“异步”属性以向返回YES 只使用子MOC的私有队列?

1 个答案:

答案 0 :(得分:0)

你的代码并不完全错误,但它比它需要的更复杂。

当您调用performBlock时,您告诉托管对象上下文在专用队列上异步执行该块。对于调用performBlock的代码,该块已经是异步的。将其包裹在NSOperation中可能是安全的,但也完全没有必要。代码调用performBlock后,NSOperation将完成,因为performBlock的异步性质。简而言之,NSOperation在这里完全没必要。

您可以将performBlock替换为performBlockAndWait,但这没有多大意义。你强迫NSOperation等待,但没有充分的理由。

除非您有其他一些未提及的异步要求,否则您提及的子类NSOperation也是不必要的。如何配置NSOperation无关紧要 - 只需摆脱它。

更新,因为在评论中您似乎执行还有其他异步要求......

  • 代码可能安全,具体取决于您的其他操作。
  • 由于performBlock立即返回,队列中的下一个操作将与另一个队列并行运行。那有关系吗?这取决于队列中的其他操作正在做什么。如果他们依赖这个performBlock已完成,那就是一个问题。您可以使用performBlockAndWait来处理此问题,以使队列保持连续。