web-dev-qa-db-ja.com

NSPersistentStoreリモート変更通知が起動されない

NSPersistentCloudKitContainerを使用するCoreData + CloudKitプロジェクトで履歴追跡を実行しようとしています。私はAppleの サンプルプロジェクト と一緒にフォローしています

リモートストアが更新されたときに特定のタスクを実行したい。このため、Appleは、アプリの署名と機能のバックグラウンドモードセクションでリモート通知を有効にすることをお勧めします。

Appleのサンプルプロジェクトに示されているように、プロジェクトの履歴追跡を有効にしました。

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

    // ...

また、ストアの変更をリッスンするためにストアを登録しました。

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

    // ...

NSPersistentStoreRemoteChangeNotificationをリッスンするオブザーバーも追加されています。

ただし、NSPersistentStoreRemoteChangeNotificationは起動されません。実装に間違いがないことを確認するために、Appleが提供するサンプルコード@objc func storeRemoteChange(_ notification: Notification)にブレークポイントを設定しただけですが、通知が発行されておらず、ブレークポイントがアクティブ化されていません。

サンプルプロジェクトで行われたタグの重複排除を理解し、テストも試みましたが、成功しませんでした。それはAppleの実装のバグですか、それとも必要なセットアップがありませんか?

5
FE_Tech

OPによって言及されたサンプルアプリをデバッグすると、次のことがわかりました。

  • XCodeバージョン11.3(11C29)の時点で、オプションキー(NSPersistentStoreRemoteChangeNotificationPostOptionKey)と通知名(.NSPersistentStoreRemoteChange)の両方にSDK定数があり、これらはサンプルの最新のダウンロードに反映されています。コード。
  • サンプルアプリは、間違ったオブジェクトのリモート変更通知に登録するため、受信することはありません。受け入れられた回答に従って送信者を変更すると、これが修正されます。
  • アプリのUIは常にクラウドから受信した変更を反映するように更新されますが、これらの更新は、リモートの変更通知ではなく、アプリのNSFetchedResultsControllerデリゲートがcontrollerDidChangeContentコールバックを使用してUIを更新することによって促されます。
  • サンプルアプリで使用される標準のNSPersistentCloudKitContainerは、クラウドから送信されたすべての更新のローカル永続ストアへの自動インポートを実行します。これは、persistentStoreが履歴追跡用に設定され、viewContextが自動更新用に設定されているためです。最新世代のデータに対して、インポートごとにUIの更新がトリガーされます。

これらの観察に基づいて、CoreData、CloudKit、およびSwiftUIの使用を指定して取得したXCodeテンプレートに基づいて、小さなアプリを最初から作成しました。サンプルアプリで設定したのと同じ方法で永続コンテナーとビューコンテキストを設定し、SwiftUIの@FetchRequestラッパーを使用してマスタービュー表示でデータを取得しました。案の定、リモートインポートの動作はまったく同じでしたなしリモート変更通知を使用し、インポートのたびにUIが更新されました。

次に、受け入れられた回答に従って、リモート変更通知に正しく登録すると、それらが受信されることを確認しました。これらは、NSPersistentCloudKitでの各受信およびインポート操作が完了した後に送信されるようです。それらのインポートによって開始されたローカルデータの変更の通知を取得するために、それらを監視する必要はありません。

1
brotskydotcom

バグかどうかわかりません。 Appleのサンプルプロジェクトをダウンロードして実行するだけですが、NSPersistentStoreRemoteChangeNotificationが起動されることはありません。

AppDelegateに同じNSPersistentStoreRemoteChangeNotificationのオブザーバーをもう1つ追加しましたが、起動しています。

AppDelegateに通知オブザーバーを追加してから、CoreDataStackのStoreRemoteChange(_:)を呼び出すだけです。また、タグ重複排除ロジックは正しく機能します。

これがAppDelegateに追加したコードです

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // The view controller hierarchy is defined in the main storyboard.
        guard let splitViewController = window?.rootViewController as? UISplitViewController,
            let navController = splitViewController.viewControllers[splitViewController.viewControllers.count - 1] as? UINavigationController,
            let topViewController = navController.topViewController else {
                return false
        }
        // Configure the splitViewController.
        topViewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
        splitViewController.delegate = self
        splitViewController.preferredDisplayMode = .allVisible

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

        return true
    }

@objc
func storeRemoteChange(_ notification: Notification) {
        coreDataStack.storeRemoteChange(notification)
}
0
FE_Tech