CoreData 和 CloudKit 同步有效,但 NSPersistentStoreRemoteChange 通知永远不会触发

CoreData and CloudKit Sync works, but NSPersistentStoreRemoteChange notification never fires

我已经更新了现有的 CoreData 应用程序以使用 CloudKit 以便它可以在多个设备之间保持数据同步(对于同一个 iCloud 帐户)。

有效!数据同步正常。

但是主 UIViewController 的视图没有反映新数据。要查看更改,我必须切换到不同的视图,然后切换回在其 viewWillAppear() 函数中调用 refreshData() 的主视图。然后它从数据存储中重新读取并显示所有数据(包括在其他设备上更新的任何数据。

UIViewController 应该根据下面的 viewDidLoad() 观察 NSPersistentStoreRemoteChange 通知:

    override func viewDidLoad() {
        super.viewDidLoad()
    //  NotificationCenter.default.addObserver(self, selector: #selector(handleRemoteChange), name: .NSPersistentStoreRemoteChange, object: AppDelegate.appDelegate().persistentContainer.persistentStoreCoordinator)
        NotificationCenter.default.addObserver(self, selector: #selector(handleRemoteChange), name: .NSPersistentStoreRemoteChange, object: nil)
    }

但是从未调用处理函数:

    @objc func handleRemoteChange(notification: Notification) {
        print("Handling remote change to data in Collection Controller")
        refreshData()
    }

那个 print 语句从不打印任何东西,那里设置的断点也从不触发。

我已将托管对象上下文配置为在创建 NSPersistentCloutKitContainer 后立即根据需要合并来自父对象的更改:

    container.viewContext.automaticallyMergesChangesFromParent = true

该应用程序具有我在网上(和 Stack Overflow)搜索线索后了解到的所有相关 iCloud 功能和权利,包括:

容器的 persistentStoreDescription 将 NSPersistentStoreRemoteChangeNotificationPostOptionKey 选项设置为 true:

        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                print("FAILED to load persistent store:\(storeDescription)\nERROR:\n\(error)\n\(error.userInfo)")
            }
        })

        container.viewContext.automaticallyMergesChangesFromParent = true
        for description in container.persistentStoreDescriptions {
            description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
        }

很明显,数据正在同步。只是通知没有按预期工作。所以最终用户不会自动看到 new/sync 的数据。

我怎样才能让它工作?

我也遇到了同样的问题。我刚刚发现它在 TestFlight 构建中工作正常,但是当直接使用 Xcode 构建时,它却没有。你试过了吗?

还请记得听取此处概述的远程更改: https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes

这似乎需要 NotificationCenter.default.addObserver object: 字段为 container.persistentStoreCoordinator 才能工作,这在 https://developer.apple.com/documentation/coredata/consuming_relevant_store_changes.

的文档中

Apple 在 https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud 的示例代码使用 object: container 但不起作用。

听众:

NotificationCenter.default.addObserver(self, selector: #selector(handleRemoteChange), name: .NSPersistentStoreRemoteChange, object: nil)

应该加在里面

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    // Here:
    NotificationCenter.default.addObserver(self, selector: #selector(handleRemoteChange), name: .NSPersistentStoreRemoteChange, object: nil)
}

不要忘记取消订阅视图将消失:

override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        NotificationCenter.default.removeObserver(self, name: .NSPersistentStoreRemoteChange, object: nil)
    }

我有同样的问题,通过 在调用 loadPersistentStores(completionHandler:)

之前配置自定义持久存储描述来解决
container = NSPersistentCloudKitContainer(name: "RubikClub")
// turn on persistent history tracking
let description = container.persistentStoreDescriptions.first
description?.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description?.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
NotificationCenter.default.addObserver(self, selector: #selector(type(of: self).storeRemoteChange(_:)), name: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator)

container.loadPersistentStores { (_, error) in
  if let error = error {
    fatalError("init core data error: \(error.localizedDescription)")
  }
}
container.viewContext.automaticallyMergesChangesFromParent = true