NSPersistentStoreRemoteChangeNotification 没有被解雇

FE_*_*ech 12 core-data cloudkit ios13 nspersistentcloudkitcontainer

我正在尝试在我的 CoreData+CloudKit 项目中执行历史跟踪,该项目使用NSPersistentCloudKitContainer. 我一直在关注 Apple 的示例项目

我想在远程存储更新后执行某些任务。为此,苹果建议在应用程序的签名和功能的后台模式部分启用远程通知。

我已经为我的项目启用了历史跟踪,如 Apple 的示例项目所示。

    // turn on persistent history tracking
    let description = container.persistentStoreDescriptions.first
    description?.setOption(true as NSNumber,
                           forKey: NSPersistentHistoryTrackingKey)

    // ...
Run Code Online (Sandbox Code Playgroud)

我还注册了我的商店来监听商店的变化。

    // turn on remote change notifications
    let remoteChangeKey = "NSPersistentStoreRemoteChangeNotificationOptionKey"
    description?.setOption(true as NSNumber,
                               forKey: remoteChangeKey)

    // ...
Run Code Online (Sandbox Code Playgroud)

还添加了观察者来侦听NSPersistentStoreRemoteChangeNotification.

然而,没有NSPersistentStoreRemoteChangeNotification被解雇。为了确保我的实现没有错误,我只是在@objc func storeRemoteChange(_ notification: Notification)Apple 提供的示例代码中放置了断点,但我仍然看不到任何通知被触发并且没有断点被激活。

我已经了解示例项目中完成的标签重复数据删除,也尝试对其进行测试,但没有任何成功。这是 Apple 实现中的错误还是我缺少任何必需的设置?

mal*_*hal 16

我的猜测是你正在观察容器而不是商店协调器,像这样添加你的观察者:

    NotificationCenter.default.addObserver(
        self, selector: #selector(type(of: self).storeRemoteChange(_:)),
        name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)
Run Code Online (Sandbox Code Playgroud)

注意最后一个参数 container.persistentStoreCoordinator

还有一个警告,这个通知出现在所有不同的线程上,所以你要小心并发。只需在方法中放置 5 秒睡眠,您就会在应用启动时看到 3 个不同的线程调用它。这可能就是为什么在示例中有一个historyQueuewith maxOperationCount1 来处理它的原因。

某些通知必须NSPersistentHistoryTokenKeyuserInfo不知道为什么。


bro*_*com 6

调试OP提到的示例应用程序,我观察到以下内容:

  • 从 XCode 版本 11.3 (11C29) 开始,选项键 ( NSPersistentStoreRemoteChangeNotificationPostOptionKey) 和通知名称 ( .NSPersistentStoreRemoteChange) 都有 SDK 常量,这些常量反映在最新下载的示例代码中。
  • 示例应用程序在错误的对象上注册远程更改通知,因此它永远不会收到任何通知。根据接受的答案更改发件人可以解决此问题。
  • 应用程序 UI 始终会更新以反映从云接收到的更改,但这些更新不是由远程更改通知提示的,而是由应用程序的NSFetchedResultsController委托使用controllerDidChangeContent回调来刷新 UI 来提示的。
  • 示例应用程序使用的标准NSPersistentCloudKitContainer是将所有云发送的更新自动导入到本地持久存储中,并且因为将 persistStore 设置为历史跟踪,并将 viewContext 设置为自动更新到最新一代的数据,每次导入都会触发 UI 更新。

基于这些观察,我根据指定使用 CoreData、CloudKit 和 SwiftUI 获得的 XCode 模板从头开始编写了一个小应用程序。我按照在示例应用程序中设置的方式设置其持久容器和视图上下文,并使用 SwiftUI 的@FetchRequest包装器来获取主视图显示中的数据。果然,我看到了完全相同的远程导入行为,而无需使用任何远程更改通知,并且每次导入后 UI 都会更新。

然后我确认,根据已接受的答案,如果我正确注册了远程更改通知,就会收到它们。它们似乎是在 NSPersistentCloudKit 中的每个接收和导入操作完成后发送的。不需要观察它们来获取由这些导入发起的本地数据更改的通知。