5

我遇到了NSPrivateQueueConcurrencyType并发类型而不是NSMainQueueConcurrencyType.

我的上下文初始化:

_managedObjectContext = [[NSManagedObjectContext alloc] 
initWithConcurrencyType:NSPrivateQueueConcurrencyType];  
[_managedObjectContext setPersistentStoreCoordinator:coordinator];

麻烦的代码:

NSManagedObjectID *managedObjectID = [self managedObjectIDForEntity:entity 
withParseObjectId:object.objectId];  
managedObject = [context existingObjectWithID:managedObjectID error:error];

回溯: 回溯

链接到 Github项目打开问题以获取问题的一些上下文。

4

1 回答 1

4

You have shot yourself in the face.

executeFetchRequest:error: creates a separate child context on which it does some work (while the parent's queue is blocked). This work involves synchronously dispatching work to the parent's queue (via insertOrUpdateObjects:).

This is because NSManagedObjectContext -existingObjectWithId: with nested contexts dispatches to the parent's queue to fulfill objects faulted in to the parent context. Unfortunately you've already blocked the parent's queue with your performBlockAndWait on the child context.

A great sadness ensues.


Edit: Thoughts on a possible solution

The problem here is caused by the use of nested contexts with different queues. I'm not sure I understand the motivation for using a nested context in this situation unless the provided context is NSMainQueueConcurrencyType.

Even then, forcing fetch work off the calling context's queue is hazardous, since any existing objects in the fetch will fall victim to this problem if they are faulted (as is being done here).

It is possible that the AFIncrementalStore somehow guarantees graph isolation in this situation. I found this issue filed against AFNetwork:

https://github.com/AFNetworking/AFIncrementalStore/commit/1f822279e6a7096327ae56a2f65ce8e2ff36da83

It is suspiciously similar in that a retain cycle prevented an object from being deallocated, thereby causing it to permanently exist in the parent context and deadlock trying to fault.

于 2014-01-13T07:11:03.627 回答