在异步操作中使用 Core Data

Using Core Data in an asynchronous operation

我有一个 iOS 同步进程分解为一系列异步 NSOperation 子类。这些被分解为进行大量处理的那些和那些依赖网络的。但他们中的大多数人也用核心数据做事。

我不确定如何在操作中执行核心数据操作。

这里有几个简单的例子......我的真实代码做了几次进出数据库上下文的切换。它还使用 @synchronize(self){}.

NSManagedContext *context = [self newContextFromParent];
__block NSString *someValue;
[context performBlockAndWait:^{
    // fetch someValue from Core Data
}];
[self doMoreWorkWithValue:someValue];
[context performBlockAndWait:^{
    NSError *e;
    if ([context hasChanges]) {
        [context saveChanges:&e];
    }
}];

从表面上看,这似乎是个好方法,但根据我在 performBlockAndWait: 中所做的工作,这里可能会出现死锁。

一般来说,我喜欢在我的代码中避免使用 performBlockAndWait:,而是使用 performBlock:

[context performBlock:^{
    NSString *someValue = @""; // fetch someValue from Core Data
    [backgroundQueue addOperationWithBlock:^{
        [self doMoreWorkWithValue:someValue withCompletion:^{
            [context performBlock:^{
                NSError *e;
                if ([context hasChanges]) {
                    [context saveChanges:&e];
                }
            }];
        }];
    }];
}];

不过,通过这种方法,我已经将我的处理从分配给我的线程转移到 backgroundQueue 决定 运行 我的进程的任何线程,我不确定是什么更好的方法是。

如果我在主操作中捕获 [NSOperation currentQueue] 并改为添加到它,我已将我的块添加到队列的末尾。我真正想要的是恢复。

我应该在这里使用什么方法?

你的第一种方法是我会使用的方法。不过,您提到了对 performBlockAndWait: 内部死锁的担忧。您是否担心调用另一个本身可能使用 performBlockAndWait: 的方法?如果是这样,不用担心; performBlockAndWait: 使用 re-entrantly 是明确安全的。即:此代码是安全的(尽管显然是人为设计的):

[context performBlockAndWait:^{
    [context performBlockAndWait:^{
        // fetch someValue from Core Data
    }];
}];

如果死锁问题与 Core Data 无关,那么您似乎在 doMoreWorkWithValue: 内部也有同样多的死锁风险,对吗?