NSPersistentCloudKitContainer 在发生 CKErrorDomain 12 错误时停止同步

问题描述 投票:0回答:0

我的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
}

有没有人遇到过类似的问题?希望得到您的帮助,谢谢!

ios swift core-data cloudkit ckerror
© www.soinside.com 2019 - 2024. All rights reserved.