【发布时间】:2022-06-11 02:19:02
【问题描述】:
我们的每个数据行都包含一个唯一的uuid 列。
以前,在采用 CloudKit 之前,uuid 列具有唯一约束。这使我们能够防止数据重复。
现在,我们开始将 CloudKit 集成到我们现有的 CoreData 中。这样的唯一约束被删除。以下用户流,会造成数据重复。
使用CloudKit时导致数据重复的步骤
- 首次启动应用。
- 由于有空数据,所以生成一个预定义
uuid的预定义数据。 - 预定义数据同步到 iCloud。
- 应用已卸载。
- 应用程序已重新安装。
- 首次启动应用。
- 由于有空数据,所以会生成带有预定义
uuid的预定义数据。 - 第 3 步中以前的旧预定义数据已同步到设备。
- 我们现在有 2 个具有相同
uuid的预定义数据! :(
我想知道,我们有没有办法防止这种重复?
在第 8 步中,我们希望有一种方法可以在写入 CoreData 之前执行此类逻辑
检查CoreData中是否存在这样的uuid。如果没有,请写入 CoreData。 如果没有,我们将选择具有最新更新日期的那个,然后覆盖 现有数据。
我曾经尝试将上述逻辑插入 https://developer.apple.com/documentation/coredata/nsmanagedobject/1506209-willsave 。为了防止保存,我使用self.managedObjectContext?.rollback()。但它只是崩溃。
您有什么想法,我可以使用哪些可靠的机制来防止 CoreData CloudKit 中的数据重复?
附加信息:
在采用 CloudKit 之前
我们正在使用以下 CoreData 堆栈
class CoreDataStack {
static let INSTANCE = CoreDataStack()
private init() {
}
private(set) lazy var persistentContainer: NSPersistentContainer = {
precondition(Thread.isMainThread)
let container = NSPersistentContainer(name: "xxx", managedObjectModel: NSManagedObjectModel.wenote)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// This is a serious fatal error. We will just simply terminate the app, rather than using error_log.
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
// So that when backgroundContext write to persistent store, container.viewContext will retrieve update from
// persistent store.
container.viewContext.automaticallyMergesChangesFromParent = true
// TODO: Not sure these are required...
//
//container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
//container.viewContext.undoManager = nil
//container.viewContext.shouldDeleteInaccessibleFaults = true
return container
}()
我们的 CoreData 数据架构有
- 唯一约束。
- 拒绝删除关系规则。
- 非空字段没有默认值。
采用 CloudKit 后
class CoreDataStack {
static let INSTANCE = CoreDataStack()
private init() {
}
private(set) lazy var persistentContainer: NSPersistentContainer = {
precondition(Thread.isMainThread)
let container = NSPersistentCloudKitContainer(name: "xxx", managedObjectModel: NSManagedObjectModel.wenote)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// This is a serious fatal error. We will just simply terminate the app, rather than using error_log.
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
// So that when backgroundContext write to persistent store, container.viewContext will retrieve update from
// persistent store.
container.viewContext.automaticallyMergesChangesFromParent = true
// TODO: Not sure these are required...
//
//container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
//container.viewContext.undoManager = nil
//container.viewContext.shouldDeleteInaccessibleFaults = true
return container
}()
我们将 CoreData 数据架构更改为
- 没有唯一约束。
- 取消关系的删除规则。
- 具有非空字段的默认值。
根据来自https://developer.apple.com/forums/thread/699634?login=true 的开发者技术支持工程师的反馈,他提到我们可以
- 通过使用存储持久历史记录检测相关更改
- 删除重复数据
但是,它应该如何实现并不完全清楚,因为提供的 github 链接已损坏。
【问题讨论】:
-
你在使用
NSPersistentCloudKitContainer吗? -
是的。对不起。请允许我通过更新我的问题来提供更多技术细节。
标签: ios swift core-data cloudkit