我们的每一行数据都包含一个唯一的uuid
列。
在采用CloudKit之前,uuid
列具有唯一约束。这使我们能够防止数据重复。
现在,我们开始将CloudKit集成到现有的CoreData中。这样的唯一约束已被删除。以下用户流程将导致数据重复。
使用CloudKit导致数据重复的步骤
- 第一次启动应用程序。
- 由于没有数据,因此将生成具有预定义
uuid
的预定义数据。 - 将预定义数据同步到iCloud。
- 卸载应用程序。
- 重新安装应用程序。
- 第一次启动应用程序。
- 由于没有数据,因此将生成具有预定义
uuid
的预定义数据。 - 从步骤3中的先前旧的预定义数据同步到设备。
- 我们现在有两个具有相同
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数据架构更改为:
- 没有唯一约束条件。
- Nullify(空值)删除关系规则。
- 为非空字段设置默认值。
根据来自https://developer.apple.com/forums/thread/699634?login=true的一位开发技术支持工程师的反馈,他提到我们可以:
- 通过消耗存储持久历史记录来检测相关的更改
- 删除重复数据
但是,它并不完全清楚应该如何实现,因为提供的github链接已经失效。
NSPersistentCloudKitContainer
? - Vadim Belyaev