CoreData 和一对多关系的并发错误
Posted
技术标签:
【中文标题】CoreData 和一对多关系的并发错误【英文标题】:Concurrency error with CoreData and one-to-many relationship 【发布时间】:2012-03-28 12:41:11 【问题描述】:我目前正在开发一个使用 CoreData 作为数据持久层的 iPhone 应用程序。在其中一种情况下,我需要在后台进行一些处理和批量更新托管对象,以免阻塞 UI 线程。
在Apple's recommendation 之后,我有 2 个不同的托管对象上下文(一个用于主线程,一个用于后台线程)。这是分配代码(在我的应用程序委托中):
// Object context for Main Thread
_managedObjectContext = [[NSManagedObjectContext alloc] init];
_managedObjectContext.persistentStoreCoordinator = _coordinator;
// Object context for the background thread
dispatch_group_t myGroup = dispatch_group_create();
dispatch_group_async(
myGroup,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),
^
_bgManagedObjectContext = [[NSManagedObjectContext alloc] init];
_bgManagedObjectContext.persistentStoreCoordinator = _coordinator;
);
dispatch_group_wait(myGroup, DISPATCH_TIME_FOREVER);
dispatch_release(myGroup);
应用启动时,主线程仅获取对象进行显示,而后台线程从网络获取新数据并更新CoreData。
我使用 AFNetworking 并确保所有回调都在后台线程上执行。片段:
NSURLRequest *request = [NSURLRequest requestWithURL:webserviceURL];
AFHTTPRequestOperation *operation =
[[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[operation setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation, id responseObject)
// Getting the managed object context created on the bg thread
NSManagedObjectContext *context = [self bgManagedObjectContext];
//
// Snip...
// Fetch objects, update them
//
failure:nil];
operation.successCallbackQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
[operation start];
在回调代码中,我根据属性获取新对象,然后更新它们。一切都很好,直到我开始更新相关对象......
我的主要实体 (Place
) 定义了与 Keyword
(穷人的全文搜索...)的单边 一对多 关系,并且当我重新索引Place
,我首先删除所有关联的Keyword
s。
// `self.searchWords` is a @dynamic property
for (NSManagedObject *word in self.searchWords)
// context is still the background thread's object context
// and we're still on the background thread
[context deleteObject:word];
[self removeSearchWords:oldSearchWords];
到达[context deleteObject:word]
时,我遇到了异常:NSManagedObjectContext 无法删除其他上下文中的对象
当我调试和检查变量时,我可以看到:
self._cd_managedObjectContext
是后台线程的对象上下文
word._cd_managedObjectContext
是主线程的对象上下文
我觉得这完全令人困惑,我不明白为什么获取的关系最终会与不同的对象上下文相关联。
我最终可以在后台上下文中重新获取关联的Keyword
,然后从这里删除它,但在这种情况下它是唯一的解决方案吗?还是我做错了什么?
【问题讨论】:
【参考方案1】:克莱门特,
我建议两件事。首先,必须在执行它们的线程上创建后台 MOC。使用 GCD,您不能永久声明任何线程。因此,这引出了我的第二点。不要坚持你的背景 MOC。它们的创建成本很低。我怀疑您的大部分问题是由于没有使 MOC 保持同步。持久性存储确实是实现这一点的机制。
安德鲁
【讨论】:
感谢您的建议,我实际上最终在需要时按需创建了后台 MOC。但是,我在问题中描述的问题仍然存在。 Clément,那么您遇到了数据库一致性问题。这对于许多多线程数据库应用程序很常见。 IOW,您没有 CD 问题。就我而言,我通过在使用对象很久之后删除对象来解决这个问题。您也可以通过从不保存瞬态对象来解决此问题。在 CD 中,这最好在单独的 MOC 中完成。然后,在完成瞬态对象后删除 MOC。安德鲁以上是关于CoreData 和一对多关系的并发错误的主要内容,如果未能解决你的问题,请参考以下文章