performBlockAndWait创build死锁

我正在写一个执行一些CoreData的东西的函数。 我希望函数只有所有的CoreData操作执行后才返回。 CoreData的东西包括在后台上下文中创build一个对象,然后在父上下文中做更多的事情:

+ (void) myFunction NSManagedObjectContext *backgroundContext = [DatabaseDelegate sharedDelegate].backgroundContext; [backgroundContext performBlockAndWait:^{ MyObject *bla = create_my_object_in:backgroundContext; [backgroundContext obtainPermanentIDsForObjects:[[backgroundContext insertedObjects] allObjects] error:nil]; [backgroundContext save:nil]; [[DatabaseDelegate sharedDelegate].parent.managedObjectContext performBlockAndWait:^{ [[DatabaseDelegate sharedDelegate].parent updateChangeCount:UIDocumentChangeDone]; // Do some more stuff NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:someOperation]; }]; }]; return; } 

我希望返回只发生在[queue addOperation:someOperation] 。 这似乎工作大部分的情况下,但我有一个案件,当这个function从来没有返回。 它似乎是僵局,我怀疑这是因为performBlockAndWait

我的问题是:

(1)有人可以解释为什么会发生这种僵局吗?

(2)实现相同function的正确方法是什么? 要求是只有在两个块都被执行后, myFunction才会返回。

谢谢!

假设你正在从主线程调用myFunction 。 让我们想象一下[DatabaseDelegate sharedDelegate].parent.managedObjectContext在主线程上被调度。

使用[backgroundContext performBlockAndWait:]您正在调度上下文专用背景队列中的块。 阻塞主线程。

使用[.parent.managedObjectContext performBlockAndWait:] ,您正在调度主线程上的一个块,阻止专用队列。

但是主线程已经被阻塞了。 所以块永远不会执行。 而performBlockAndWait:永远不会返回。

僵局。

使用asynchronous调度的块和完成块。

你不必等待。 你的后台工作执行,然后, 在它完成之前 ,它开始在主线程上工作,在它完成之前,它执行你的“一些操作”。 你可以用asynchronous代替它,它仍然可以工作。

看这个代码,没有理由使用阻塞版本…

 + (void) myFunction { NSManagedObjectContext *backgroundContext = [DatabaseDelegate sharedDelegate].backgroundContext; [backgroundContext performBlock:^{ // Asynchronous... but every command in this block will run before this // block returns... MyObject *bla = create_my_object_in:backgroundContext; [backgroundContext obtainPermanentIDsForObjects:[[backgroundContext insertedObjects] allObjects] error:nil]; [backgroundContext save:nil]; [[DatabaseDelegate sharedDelegate].parent.managedObjectContext performBlock:^{ // Asynchronous, but this whole block will execute... [[DatabaseDelegate sharedDelegate].parent updateChangeCount:UIDocumentChangeDone]; // Do some more stuff // This will not run until after the stuff above in this block runs... NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperation:someOperation]; }]; // You will reach here BEFORE the code in the previous block executes, but // the "someOperation" is in that block, so it will not run until that // block is done. }]; // Likewise, you will reach here before the above work is done, but everything // will still happen in the right order relative to each other. return; }