现在我两天以来一直在head头,这归咎于开发人员和我自己。因此,我去尝试简化示例并尝试理解该标志:
-com.apple.CoreData.ConcurrencyDebug 1
在viewDidLoad方法中添加了简单代码:
NSFetchRequest *fr = [NSFetchRequest fetchRequestWithEntityName:@"Event"];
_events = [self.pc.viewContext executeFetchRequest:fr error:nil];
Event *event = _events.firstObject;
NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
NSManagedObjectID *objID = [event objectID];
[opQueue addOperationWithBlock:^{
NSManagedObjectContext *context = self.pc.newBackgroundContext;
Event *bgEvent = [context objectWithID:objID]; // Thread 5: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
}];
运行该应用程序并发生此崩溃(请在最后一行之前检查注释1行)
因此,我正在尝试将主MOC对象移动到后台MOC并崩溃。
在不同线程的MOC之间传递对象时,我会丢失某些东西吗?
注意:pc
只是由向导创建并存储在此控制器的strong
属性中的persistentContainer。是的,它具有存储和正确的URL,这很好,如果我删除了这段代码,该应用程序将不会崩溃。在向Event
实体添加了一些行之后,我添加了此代码,以便获取对象。
答案 0 :(得分:1)
您不能在任意队列上的NSManagedObjectContext上进行操作。您需要使用上下文的队列。这意味着将您对objectWithID:
的呼叫包装到context.perform()
(异步)或context.performAndWait()
(同步)中。
通常来说,您应该使用上下文的队列而不是创建自己的NSOperationQueue
,但是如果出于某种原因需要自己的队列,那就很好了。您只需要将上下文的队列用于上下文的操作即可。
有关详细信息,请参见Core Data Programming Guide: Concurrency。
根据您的评论,您已经写了以下内容:
NSManagedObjectID *objID = [event objectID];
[self.pc.viewContext performBlockAndWait:^{
NSManagedObjectContext *context = self.pc.newBackgroundContext;
Event *bgEvent = [context objectWithID:objID];
}];
那是不正确的,也是造成问题的原因。您不能在context
的队列中使用viewContext
。我相信您的意思是:
NSManagedObjectID *objID = [event objectID];
NSManagedObjectContext *context = self.pc.newBackgroundContext
[context performBlock:^{
Event *bgEvent = [context objectWithID:objID];
....
}];
您需要在自己的context
中使用perform block
,而不是其他上下文的perform
块。
在这里使用performBlockAndWait
是没有意义的,因为那样会阻塞主队列。相反,这将在后台队列上异步执行此阻止,我相信这是您要尝试执行的操作。