我仍然对如何使用NSPersistentContainer performBackgroundTask
创建实体并保存它感到困惑 . 通过在 performBackgroundTask() { (moc) in }
块中调用方便方法 init(context moc: NSManagedObjectContext)
创建实例后,如果我检查 container.viewContext.hasChanges
,则返回false并说没有什么要保存,如果我在 moc
上调用save(为此块创建的后台MOC),我会收到如下错误:
致命错误:无法保存上下文:错误域= NSCocoaErrorDomain代码= 133020“无法合并更改 . ”的UserInfo = {conflictList =(
“NSMergeConflict(0x17466c500)for NSManagedObject(0x1702cd3c0)with objectID'0xd000000000100000 <x-coredata:// 3EE6E11B-1901-47B5-9931-3C95D6513974 / Currency / p4>'with oldVersion = 1 and newVersion = 2 and old cached row = 致命错误:无法保存上下文:错误Domain = NSCocoaErrorDomain Code = 133020“无法合并更改 . ”UserInfo = {conflictList =(
“NSMergeConflict(0x170664b80)for NSManagedObject(0x1742cb980)with objectID'0xd000000000100000 <x-coredata:// 3EE6E11B-1901-47B5-9931-3C95D6513974 / Currency / p4>'with oldVersion = 1 and newVersion = 2 and old cached row = 和新数据库row = “
)}
所以我没有得到并发工作,如果有人能向我解释在iOS 10中对核心数据使用此功能的正确方法,我将非常感激
1 回答
TL:DR :您的问题是您正在使用
viewContext
和背景上下文进行编写 . 您应该只以一种同步方式写入核心数据 .Full explanation: 如果一个对象同时从两个不同的上下文中更改,则核心数据并不是一个很好的解决方案,因为您可以通过这种方式丢失数据 . 很多专业人员长期处理这个问题的方式是有一个操作队列来排队写入,所以一次只进行一次写入,并且主线程上只有读取的另一个上下文 . 这样你就不会遇到任何合并冲突 . (有关此设置的详细说明,请参阅https://vimeo.com/89370886) .
使用
NSPersistentContainer
进行此设置非常简单 . 在核心数据管理器中创建一个NSOperationQueue并使用此队列写所有内容:
当您调用
enqueueCoreDataBlock
时,该块将入队以确保没有合并冲突 . 但是如果你写入viewContext
会破坏这种设置 . 同样,您应该将您创建的任何其他上下文(使用newBackgroundContext
或performBackgroundTask
)视为只读,因为它们也将位于写入队列之外 .起初我以为
NSPersistentContainer
的performBackgroundTask
有一个内部队列,初始测试支持它 . 经过更多测试后,我发现它也可能导致合并冲突 .