我正在编写一个执行一些CoreData内容的函数。我希望函数在所有CoreData操作执行完之后只返回。 CoreData的东西包括在后台上下文中创建一个对象,然后在父上下文中做更多的东西:
+ (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]
之后。
这似乎适用于大多数情况,但我有一个案例,当这个函数永远不会返回。它似乎陷入僵局,我怀疑这是因为performBlockAndWait
。
我的问题是:
(1)有人可以解释为什么会出现这种僵局吗?
和
(2)实现相同功能的正确方法是什么?要求是myFunction
仅在两个块都被执行后才返回。
谢谢!
答案 0 :(得分:11)
让我们假设您从主线程中调用myFunction
。我们假设[DatabaseDelegate sharedDelegate].parent.managedObjectContext
被安排在主线程上。
使用[backgroundContext performBlockAndWait:]
,您将在上下文专用后台队列上调度一个块。阻止主线程。
使用[.parent.managedObjectContext performBlockAndWait:]
,您正在主线程上调度一个块,阻塞专用队列。
但是主线程已被阻止。所以块永远不会执行。而performBlockAndWait:
永远不会回来。
死锁。
使用带有完成块的异步调度块。
答案 1 :(得分:2)
你不必等待。你的后台工作会在完成之前执行,它会启动主线程上的工作,在完成之前,它会执行你的“someOperation”。你可以用异步替换它,它仍然可以工作。
查看此代码,没有理由使用阻止版本...
+ (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;
}