我正在尝试使用新的核心数据API NSPersistentContainer,并且给人的印象是内部排队机制将阻止写入事务同时进行评估,如以下堆栈溢出答案NSPersistentContainer concurrency for saving to core data所述
但是,如果在每次迭代中使用performBackgroundTask
插入紧密共享一个关系目标的多个实体,则在保存上下文时会出现NSMergeConflict
错误:
let bundlePath = Bundle.main.resourceURL!
let directoryEnumerator = FileManager.default.enumerator(at: bundlePath, includingPropertiesForKeys: [URLResourceKey.isDirectoryKey, URLResourceKey.nameKey])
while let url = directoryEnumerator?.nextObject() as? URL {
if url.pathExtension == "jpeg" {
let imageData = try! Data(contentsOf: url)
DataManager.persistentContainer.performBackgroundTask { (context) in
// context.mergePolicy = NSMergePolicy.overwrite
let new = Photo(context: context)
new.name = url.lastPathComponent
new.data = imageData as NSData
let corresponding = try! context.existingObject(with: DataManager.rootFolder.objectID) as! Folder
new.parent = corresponding
try! context.save()
}
}
我在github上发布了一个示例项目来演示该问题:
https://github.com/MaximeBoulat/NSPersistentContainer_Merge_Conflict
崩溃似乎正在发生,因为多个实体正在为同一父级同时设置其“父级”关系,这会导致父级的“子级”关系在并发更新之间不同步。
即使我将传入上下文的
.automaticallyMergesChangesFromParent
属性设置为true,也会发生这种情况。我可以通过定义传入上下文的合并策略来防止崩溃,但这不是可接受的解决方案。有什么方法可以配置NSPersistentContainer来正确地序列化使用
performBackgroundTask
API调度的更新。还是我缺少某种导致这些更新相互冲突的东西?还是苹果公司向NSPersistentContainer堆栈提供了期望,即传递给performBackgroundTask
的评估逻辑时遇到的任何冲突要么是致命的,要么是被忽略的? 最佳答案
我写了您引用的答案。我错了。我已经更新了。
我发现NSPersistentContainer
的performBackgroundTask
没有功能正常的内部队列,它可能导致合并冲突。当我最初对其进行测试时,似乎确实如此,但是我发现像您一样存在冲突。幸运的是,创建自己的队列并不难解决。我知道苹果发布如此破损的东西似乎很奇怪,但事实确实如此。
很抱歉发布了不正确的信息。