我的app使用NSPersistentCloudKitContainer实现Coredata和iCloud同步数据
最近收到网上用户反馈数据同步错误,错误代码为CKErrorDomain 12
在App中,我使用
NSPersistentCloudKitContainer.eventChangedNotification
来监控同步状态,下面是具体代码
NotificationCenter.default.publisher(for: NSPersistentCloudKitContainer.eventChangedNotification)
.sink(receiveValue: { notification in
if let cloudEvent = notification.userInfo?[NSPersistentCloudKitContainer.eventNotificationUserInfoKey]
as? NSPersistentCloudKitContainer.Event {
let event = SyncEvent(from: cloudEvent)
}
})
.store(in: &disposables)
当用户反馈数据无法同步时,从上面的代码可以看出CoreData + iCloud在导出数据时出错了
同时cloudKitEvent.error不包含任何错误信息,只有
CKErrorDomain 12
这个信息,完全不知道如何排错
更可怕的是,当出现
CKErrorDomain 12
错误时,app的同步服务会立即停止。尝试重启应用程序或重启手机,并在系统中关闭iCloud同步,不会使同步服务再次工作。
只有卸载重装才能彻底解决这个问题,但是用户卸载后也会丢失一些数据,因为在错误发生时,用户产生的任何数据都没有成功同步到iCloud,所以卸载后这些数据都会丢失。
下面是CoreDataStack初始化的代码
private func setupContainer(allowCloudKitSync: Bool) -> NSPersistentCloudKitContainer {
let container = NSPersistentCloudKitContainer(name: containerName)
let privateStoreURL = containerURL.appendingPathComponent(privateStoreName)
let privateDescription = NSPersistentStoreDescription(url: privateStoreURL)
let privateOpt = NSPersistentCloudKitContainerOptions(containerIdentifier: identifier)
privateDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
privateDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
"allowCloudKitSync = \(allowCloudKitSync)".debugLog("CoreDataStack")
if allowCloudKitSync {
privateDescription.cloudKitContainerOptions = privateOpt
} else {
privateDescription.cloudKitContainerOptions = nil
}
container.persistentStoreDescriptions = [privateDescription]
container.loadPersistentStores(completionHandler: { [weak self] (storeDescription, error) in
if let error = error as NSError? {
self?.dbStatePublish.send(.loadError)
#if DEBUG
"Unresolved error \(error), \(error.userInfo)".debugLog("CoreDataStack")
#endif
} else {
if storeDescription.cloudKitContainerOptions == nil {
self?.coreDataState = .local
} else {
self?.coreDataState = .cloud
}
"load coredata status = \(String(describing: self?.coreDataState))".debugLog("CoreDataStack")
}
})
//let options = NSPersistentCloudKitContainerSchemaInitializationOptions()
//try? container.initializeCloudKitSchema(options: options)
container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
container.viewContext.transactionAuthor = appTransactionAuthorName
// Pin the viewContext to the current generation token and set it to keep itself up to date with local changes.
container.viewContext.automaticallyMergesChangesFromParent = true
do {
try container.viewContext.setQueryGenerationFrom(.current)
} catch {
fatalError("###\(#function): Failed to pin viewContext to the current generation:\(error)")
}
// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(self,
selector: #selector(storeRemoteChange(_:)),
name: .NSPersistentStoreRemoteChange,
object: container.persistentStoreCoordinator)
return container
}
有没有人遇到过类似的问题?希望得到您的帮助,谢谢!