TL;DR:通过调用
initializeCloudKitSchema
,确保 CloudKit 的 Schema 与本地数据模型一致,避免 Core Data 和 SwiftData 的 iCloud 同步不完整问题。首次启用同步或更新模型后调用一次即可。
问题背景
在 iOS 开发中,当使用 Core Data 或 SwiftData 实现 iCloud 数据同步时,开发者经常会遇到数据同步不完整的问题。某些操作能正常同步,而另一些新建的数据却无法同步到云端。这种情况通常与 CloudKit Schema 的创建有关。
为什么需要 initializeCloudKitSchema?
当你在 CloudKit Dashboard 中发现本地数据模型与云端 Schema 不一致时,很可能是因为没有正确使用 initializeCloudKitSchema
方法。虽然在模型简单的情况下,CloudKit 可能会在创建首条数据时自动生成 Schema,但当遇到以下情况时,自动创建往往会失败:
- 数据模型包含复杂的关系
- 首次创建数据时没有涉及所有关系对象
- 模型结构发生更改
正确使用 initializeCloudKitSchema 的时机
需要在以下两种情况下使用 initializeCloudKitSchema
:
- 首次启用 iCloud 同步功能时
- 对本地数据模型进行修改后
Core Data 中的实现方式
在 Core Data 中,需要在 NSPersistentCloudKitContainer
加载完成后调用 initializeCloudKitSchema
:
Swift
let container = NSPersistentCloudKitContainer(name: "Model", managedObjectModel: mom)
container.persistentStoreDescriptions = [desc]
container.loadPersistentStores { _, err in
if let err {
fatalError(err.localizedDescription)
}
}
// 在存储加载完成后初始化 CloudKit Schema
try container.initializeCloudKitSchema() // 执行后可注释此行
SwiftData 中的实现方式
SwiftData 的实现稍微复杂一些,需要先将 SwiftData 模型转换为 Core Data 的 NSManagedObjectModel
:
Swift
let config = ModelConfiguration()
do {
#if DEBUG
try autoreleasepool {
let desc = NSPersistentStoreDescription(url: config.url)
let opts = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.example.Trips")
desc.cloudKitContainerOptions = opts
desc.shouldAddStoreAsynchronously = false
if let mom = NSManagedObjectModel.makeManagedObjectModel(for: [Trip.self, Accommodation.self]) {
let container = NSPersistentCloudKitContainer(name: "Trips", managedObjectModel: mom)
container.persistentStoreDescriptions = [desc]
container.loadPersistentStores { _, err in
if let err {
fatalError(err.localizedDescription)
}
}
try container.initializeCloudKitSchema()
if let store = container.persistentStoreCoordinator.persistentStores.first {
try container.persistentStoreCoordinator.remove(store)
}
}
}
#endif
modelContainer = try ModelContainer(for: Trip.self, Accommodation.self,
configurations: config)
} catch {
fatalError(error.localizedDescription)
}
注意事项
initializeCloudKitSchema
只需在每次更新数据模型后执行一次- 执行完成后,可以注释掉相关代码