核心数据和 cloudkit 同步 wwdc 2019 不适用于 beta 3

Posted

技术标签:

【中文标题】核心数据和 cloudkit 同步 wwdc 2019 不适用于 beta 3【英文标题】:Core data and cloudkit sync wwdc 2019 not working for beta 3 【发布时间】:2019-07-06 12:14:42 【问题描述】:

我正在尝试复制 WWDC 关于将核心数据与云工具包自动同步的结果。

我尝试了三种方法:

    制作一个新的主从视图应用程序并按照步骤 wwdc 2019 演讲,在这种情况下不会发生同步

    在这种情况下,下载示例 wwdc 2019 应用程序也不会发生同步

    我制作了一个带有小核心数据和云工具包容器的小应用程序,在这种情况下会发生同步,但我必须重新启动应用程序。我怀疑它与历史管理有关,所以观察到 NSPersistentStoreRemoteChange 通知没有收到任何东西。

感谢任何帮助。

【问题讨论】:

【参考方案1】:

我也玩过 CoreData 和 iCloud,它运行良好。我想列出一些可以帮助您更进一步的要点:

你必须使用 iCloud Acc 在真实设备上运行应用程序 我们现在可以在模拟器上测试 iCloud Sync,但它不会自动收到通知。我们必须通过选择 Debug > Trigger iCloud Sync 手动触发 确保您在应用中添加了Push NotificationiCloud 功能。确保 iCloud 容器没有出现 Dave 问题(在这种情况下,您将在 Xcode 中的 iCloud 会话上看到红色文本) 为了自动刷新视图,您需要将此行添加到您的核心数据堆栈中:container.viewContext.automaticallyMergesChangesFromParent = true

代码:

public lazy var persistentContainer: NSPersistentCloudKitContainer = 
        /*
         The persistent container for the application. This implementation
         creates and returns a container, having loaded the store for the
         application to it. This property is optional since there are legitimate
         error conditions that could cause the creation of the store to fail.
         */
        let container = NSPersistentCloudKitContainer(name: self.modelName)
        container.viewContext.automaticallyMergesChangesFromParent = true
        container.loadPersistentStores(completionHandler:  (storeDescription, error) in
            if let error = error as NSError? 
                // Replace this implementation with code to handle the error appropriately.
                // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.

                /*
                 Typical reasons for an error here include:
                 * The parent directory does not exist, cannot be created, or disallows writing.
                 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
                 * The device is out of space.
                 * The store could not be migrated to the current model version.
                 Check the error message to determine what the actual problem was.
                 */
                fatalError("Unresolved error \(error), \(error.userInfo)")
            
        )
        return container
    ()
当你添加一些数据时,通常你应该看到控制台日志以CloudKit: CoreData+CloudKit: ..........开头 有时数据不会立即同步,在这种情况下,我强制关闭应用并构建一个新应用,然后数据会同步。 有一次,数据在几个小时后同步:(

【讨论】:

谢谢!我还没有尝试过的唯一提示是我没有把它放在设备上并且一直在模拟器上测试它,因为我没有两个版本 13 的 ios 设备。感谢你的回复,当我在真实设备上测试时在这里回复。但是您还提到,在您的情况下,同步有时也不会“无缝”发生。我想知道是否与测试版有关。 我在一台设备和一台模拟器上进行了测试,当在模拟器上推送数据时,我自己的应用程序和苹果示例演示在设备上都没有收到任何东西 我不认为 iCloud 同步可以在模拟器上运行。您可以将其安装在设备上,查看您的数据是否正在同步到 iCloud 仪表板。您可以删除该应用并重新安装,然后 iCloud 上的数据应该会同步到您的设备 @Albert - 不要忘记打开后台模式(远程通知) 我发现在 CoreDataCloudKitDemo 中,自动同步的效果与您提到的所有内容一样好,但从未调用过“storeRemoteChange”方法。不知道为什么。似乎 description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) 不起作用。【参考方案2】:

我发现 NSPersistentStoreRemoteChange 通知是由 NSPersistentStoreCoordinator 发布的,而不是由 NSPersistentCloudKitContainer 发布的,所以下面的代码解决了这个问题:

// Observe Core Data remote change notifications.
NotificationCenter.default.addObserver(
        self, selector: #selector(self.storeRemoteChange(_:)),
        name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)

【讨论】:

【参考方案3】:

还遇到了未发送 .NSPersistentStoreRemoteChange 通知的问题。

来自 Apple 示例的代码:

// Observe Core Data remote change notifications.
        NotificationCenter.default.addObserver(
            self, selector: #selector(type(of: self).storeRemoteChange(_:)),
            name: .NSPersistentStoreRemoteChange, object: container)

我的解决方案是不将容器设置为通知对象,而是 nil。是否无论如何都没有使用并阻止收到通知:

// Observe Core Data remote change notifications.
        NotificationCenter.default.addObserver(
            self, selector: #selector(type(of: self).storeRemoteChange(_:)),
            name: .NSPersistentStoreRemoteChange, object: nil)

更新: 根据这个答案:https://***.com/a/60142380/3187762 正确的方法是将 container.persistentStoreCoordinator 设置为对象:

// Observe Core Data remote change notifications.
        NotificationCenter.default.addObserver(
            self, selector: #selector(type(of: self).storeRemoteChange(_:)),
            name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)

【讨论】:

对“nil”的更改对我有用。我现在正在处理通知以了解何时发生真正的变化。有很多关于非事件的通知。 我认为您观察到了误报。这篇文章建议与接受的答案相反***.com/questions/59158513/… 好点,没有尝试,但似乎是一个有效的解决方案。用这个更新了我的答案。【参考方案4】:

我遇到了同样的问题,原因是必须在您的设备中启用 iCloudDrive。在每台设备的设置中检查它

【讨论】:

【参考方案5】:

我知道这个答案来晚了,并且 实际上并不具体到 OP 所指的 WWDC 19 SynchronizingALocalStoreToTheCloud Apple's sample project,但我有 同步问题(不是在启动时,当它同步正常时,但仅在应用程序处于活动状态但空闲期间,这似乎是原始问题的案例 3) 在使用 Core Data + CloudKit 和 NSPersistentCloudKitContainer 的项目中,我相信我遇到了同样的问题 - 现在显然我已解决 - 可能会影响将来阅读此问题的其他用户。

我的应用从一开始就是使用 Xcode 的 11 Master-Detail 模板和 Core Data + CloudKit 构建的,所以最初我只需要做很少的同步工作:

    在我的目标的签名和功能中启用远程通知后台模式; 为 CloudKit 添加 iCloud 功能; 选择容器iCloud.com.domain.AppName 添加viewContext.automaticallyMergesChangesFromParent = true

基本上,我关注了Getting Started With NSPersistentCloudKitContainer by Andrew Bancroft,这足以让 MVP在设备(Catalina、iOS 13、iPadOS 13)之间同步,不仅是在启动时,而且在应用程序运行和激活时也是如此(感谢上面的步骤 4)和另一个设备编辑/添加/删除了一个对象。作为 Xcode 模板,它没有 WWDC 2019 示例项目的额外自定义/高级行为,但它实际上完成了目标好吧,我很满意,所以我继续开发这个应用程序的其他部分,不再考虑同步。

几天前,我注意到 iOS/iPadOS 应用程序现在只在启动时同步,而不是在应用程序在屏幕上处于活动和空闲状态时同步;在 macOS 上,行为略有不同,因为在重新激活应用程序时,一个简单的命令选项卡触发了同步,但同样,如果 Mac 应用程序位于最前面,则不会同步来自其他设备的更改。

我最初指责我在此期间所做的一些修改:

为了在共享扩展中访问 sqlite,我通过继承 NSPersistentCloudKitContainer 将容器移动到应用组中; 我更改了应用名称的大小写,由于无法删除 CloudKit 数据库,我创建了一个名为 iCloud.com.domain.AppnameApp 的新容器 (CloudKit 是显然,不区分大小写,是的,我真的应该开始不太关心这些事情了)

虽然我很确定在每次这些更改之后我看到同步工作以及之前的工作,但同步(显然)突然中断至少几个小时让我确信这些修改中的任何一个都不是默认的path 导致在应用程序处于活动状态时停止接收通知,然后合并只会在启动时发生,正如我所看到的,因为正在运行的应用程序没有意识到更改。

我应该提一下,因为这可以帮助在我的情况下的其他人,我确信通知是在 Core Data 上下文保存时触发的,因为 CloudKit Dashboard 显示正在发送的通知:

所以,我尝试了几次清除派生数据(永远不知道),删除所有设备上的应用程序并重置 CloudKit 仪表板中的开发环境(我在开发过程中已经定期这样做了),但我仍然有没有收到通知的问题。

最后,我意识到重置 CloudKit 环境并删除应用程序确实很有用(我实际上重新启动了所有东西只是为了安全 ;)但是我还需要删除应用程序数据来自 iCloud (在从其他设备中删除后,在最后一个仍安装了该应用程序的 iOS 设备上的 iCloud 设置屏幕上)如果我真的想要一个干净的状态;否则,我有些混乱的数据库会同步回新安装的应用程序。

确实,具有全新开发环境、新安装的应用程序和重新启动的设备的真正干净的状态在应用程序位于最前面时也会恢复从设备检测到的通知。所以,如果你觉得你的设置是正确的并且已经阅读了足够多的时间viewContext.automaticallyMergesChangesFromParent = true是你唯一需要的东西,但仍然看不到来自其他设备的变化,不要排除某些东西可能已经超出你的控制范围 (不要误会我的意思:我 100% 确定这一定是我所做的!) 并尝试重新开始......这可能看起来晦涩难懂,但 我们为应用选择的同步方法有什么问题?

【讨论】:

对此的简短更新,以防@cfd1982 的这些(伟大)说明对您不起作用。如果您通过description.cloudKitContainerOptions?.databaseScope = .public 将 NSPersistentStoreDescription 设置为与公共数据库而不是私有数据库(我相信 iOS 14 之前的默认值)交互,它只会按设计每 30 分钟轮询一次来自 cloudkit 的更改(请参阅 10:30 到有关此主题的 WWDC 2020 会议视频:developer.apple.com/videos/play/wwdc2020/10650)

以上是关于核心数据和 cloudkit 同步 wwdc 2019 不适用于 beta 3的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中将 Core Data 与 Cloudkit 和许多设备同步

核心数据 + iCloud 同步 NSPersistentStoreDidImportUbiquitousContentChangesNotification

CloudKit 分享

CloudKit - 具有依赖关系的 CKQueryOperation

将使用核心数据的 iOS 应用同步到云端

CloudKit 离线存储