【发布时间】:2020-10-23 15:53:45
【问题描述】:
我有一个 Core Data+CloudKit 配置,我需要为用户提供一些初始数据作为起点。它只有几个记录/对象,所以起初我尝试对数据进行硬编码并在首次启动时写入 Core Data。然后,用户可以添加和更改起点数据。
当我启用 CloudKit 同步时,我发现当启动同一帐户上的第二台设备时,从 CloudKit 的角度来看,该设备新写入的默认数据是“更新的”。这意味着第二台设备上的默认数据将同步并覆盖用户自己在第一台设备上的数据。这很糟糕。
我相信正确的解决方案是在应用程序中提供预填充的核心数据文件 (.sqlite) 文件,以便在首次启动时,默认数据已经比用户在其他设备上创建的任何数据都旧。大多数教程和示例代码都非常旧,参考 Swift 3、Xcode 7 等。我正在寻找一个在使用 NSPersistentCloudKitContainer 时有效的解决方案。
我尝试了this SO question 答案中的代码,将persistentContainer 的类型更改为NSPersistentCloudKitContainer。这会编译并运行,但结果是我的应用程序在没有预加载数据的情况下启动,我不知道为什么。我在我的 Xcode 项目中包含了三个 .sqlite 文件,并将它们添加到“构建阶段”中的“复制捆绑资源”列表中。
这是我的代码:
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let appName = Bundle.main.infoDictionary!["CFBundleName"] as! String
let container = NSPersistentCloudKitContainer(name: appName)
//Pre-load the default Core Data (Category names) on first launch
var persistentStoreDescriptions: NSPersistentStoreDescription
let storeUrl = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!.appendingPathComponent(appName + ".sqlite")
let storeUrlFolder = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).first!
if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: appName, withExtension: "sqlite")
let seededDataUrl2 = Bundle.main.url(forResource: appName, withExtension: "sqlite-shm")
let seededDataUrl3 = Bundle.main.url(forResource: appName, withExtension: "sqlite-wal")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)
try! FileManager.default.copyItem(at: seededDataUrl2!, to: storeUrlFolder.appendingPathComponent(appName + ".sqlite-shm"))
try! FileManager.default.copyItem(at: seededDataUrl3!, to: storeUrlFolder.appendingPathComponent(appName + ".sqlite-wal"))
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
【问题讨论】:
-
我已经取得了一些进展,并了解到在从应用程序实例保存它们然后在 Xcode 中安装的过程中,.sqlite 文件很容易损坏。发生这种情况时,应用程序无法在启动时读取数据,但也不会报告错误。一旦我得到未损坏的文件,它就开始正常工作。所以现在我可以成功安装默认数据,但这已经发现了其他问题。当我弄清楚发生了什么,或者当我能提出一个合理的问题时,我会更新这个页面。
-
我发现 sqlite 文件不太可能容易损坏。保存数据,关闭应用程序并将其复制到另一个文件夹就可以了。
标签: ios swift core-data cloudkit nspersistentcloudkitcontainer