寻找 Core Data 到 CloudKit 公共数据库同步以及删除和订阅工作的工作示例

zee*_*han 5 database core-data ios swift cloudkit

经过多天的尝试但没有成功后,我在这里发布这个问题,希望有人可以帮助我解决这个看起来相当简单的问题。我正在为Swift项目而不是SwiftUI执行此操作。

我的要求非常简单,我很困惑为什么苹果的文档或其他任何地方都没有明确的解决方案。我希望在我的 iOS 应用程序上有一个从 CloudKit 同步到应用程序核心数据的公共和私有数据库,反之亦然。

我已经看过 WWDC 视频和示例代码好几次了。如果他们在工作,我就不会在这里发布我的问题。

最新 WWDC2022 视频中的人正在展示 WWDC2019 视频中的代码。而且您下载的代码与他在视频中显示的代码不同。对于这样一个简单的任务来说,这个下载的代码不仅过于复杂和混乱,而且它也不处理公共数据库同步和/或订阅。苹果的教程工作太糟糕了。

经过一番努力,我也设法找到了 WWDC2019 代码,但它无法在较新的 Xcode 上编译。我正在使用 Xcode 13。我将其修复为可在 Xcode 上运行。但最终,它并没有按预期与 CloudKit 同步。

我查阅了无数的例子,但它们都已经过时了。我还没有看到一个显示最新 CloudKit 屏幕的示例。大多数示例仅讨论私有数据库同步,这是一个相当简单且直接的过程。几乎没有任何示例谈论设置订阅,更不用说公共数据库了。通过订阅设置公共数据库的唯一示例位于 Hacking With Swift 网站,但它没有讨论将 Core Data 与 CloudKit 同步,而是直接从 CloudKit 中保存和读取。

Apple 自己的示例也仅适用于私有数据库同步。

经过许多天的挣扎和挫折,我来到这里。我从各种示例中精心挑选了工作代码片段。但最终我没能让事情顺利进行。

我在下面发布我的代码。当在设备上运行时,它会在 CloudKit 上创建记录。它也应该创建订阅,但并不是每次都创建它们。即使创建了订阅,它们也不会被可靠地触发。有时他们会被解雇,有时则不会。这是CloudKit的开发环境的问题吗?我尝试过设置多个 CloudKit 容器,但这个问题仍然存在。

此外,模拟器和真实设备上的行为并不相同。在 Simulator 上,我知道您不会收到推送通知,但即使启动应用程序也不会每次都从 CloudKit 下载记录。因此,有时它会按预期工作,而有时则根本不起作用。尽管日志不断显示它们与 CloudKit 后端正在进行某种通信。

无论如何,在 CloudKit 上删除记录并不会在设备上删除它。

运行 WWDC2022 视频提供的示例也非常不稳定。它应该创建帖子项目。它确实如此,但是无论我设置私有数据库订阅还是公共数据库订阅,同步工作都非常不可靠。删除了还是不行。通知也不起作用,尽管我在我的应用程序中设置得很好appdelegate

那么,有没有可行的解决方案可供参考?任何帮助将不胜感激。

lazy var persistentContainer: NSPersistentCloudKitContainer = {
        let container = NSPersistentCloudKitContainer(name: "PublicDB")
        
        let store = container.persistentStoreDescriptions.first!
        let storesURL = store.url!.deletingLastPathComponent()
        store.url = storesURL.appendingPathComponent("public.sqlite")
        store.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
        store.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        store.cloudKitContainerOptions?.databaseScope = .public
        
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        
        let database = CKContainer(identifier: "iCloud.com.xxxxxx.DemoApp").publicCloudDatabase
        let subscription = CKQuerySubscription(recordType: "CD_My_Entity", predicate: NSPredicate(value: true), options: [.firesOnRecordCreation, .firesOnRecordDeletion, .firesOnRecordUpdate])

        let notification = CKSubscription.NotificationInfo()
        notification.shouldSendContentAvailable = true
        notification.alertBody = "There's a new change in the db."
        notification.soundName = "default"
        subscription.notificationInfo = notification

        database.save(subscription) { result, error in
            if let error = error {
                print("<><><><><><><>")
                print(error.localizedDescription)
                print("<><><><><><><>")
            }
        }
        
        //Load the persistent stores
        container.loadPersistentStores(completionHandler: { (_, error) in
            guard let error = error as NSError? else { return }
            fatalError("###\(#function): Failed to load persistent stores:\(error)")
        })

        return container
    }()

[![enter image description here][1]][1]


  [1]: https://i.stack.imgur.com/dRTwF.png
Run Code Online (Sandbox Code Playgroud)

编辑 2022 年 9 月 4 日 自从我在大约一个月前发布这个问题并一直在研究我的应用程序的其他部分以来,在这一个月里我注意到订阅和同步有时可以在几秒钟内完美地同步所有设备。而在其他时候,它们根本不起作用。在此期间我根本没有触及上面的代码,因为我计划在应用程序的其他部分完成后再回来处理它。有时,当我早上开始工作时,我会看到我的设备与前一天完美同步。很明显,问题出在 iCloud 的开发环境上,而不是上面的代码上。我会密切关注这种行为,直到我将我的应用程序投入生产。

zee*_*han 0

现在我的应用程序已经投入生产并且工作得很好,我的观察是我在问题中发布的问题与苹果的开发环境有关。在生产中我没有看到任何问题,代码与上面的问题相同。

然而删除的问题仍然存在。删除不会同步。