core-datacloudkitios13nspersistentcloudkitcontainer

NSPersistentStoreRemoteChangeNotification not getting fired


I am trying to perform history tracking in my CoreData+CloudKit project which uses NSPersistentCloudKitContainer. I have been following along with Apple's sample project

I want to perform certain task when the remote store has been updated. For this apple recommends enabling remote notification in the Signing & capabilities's Background Mode section of the app.

I have enabled History Tracking for my project as shown in Apple's sample project.

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

    // ...

Also I have registered my store to listen for store changes.

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

    // ...

Observer is also added to listen for NSPersistentStoreRemoteChangeNotification.

However there is no NSPersistentStoreRemoteChangeNotification being fired. To make sure there is no mistake in my implementation, I am have simply put breakpoints in @objc func storeRemoteChange(_ notification: Notification) the Apple's provided sample code but still I can not see any notification being fired and no breakpoints are activated.

I have understood the deduplication of the Tags done in the sample project and also tried testing it but without any success. Is it a bug in the Apple's implementation or am I missing any setup which is required?


Solution

  • My guess is you are observing the container instead of the store coordinator, add your observer like this:

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

    Note the last param container.persistentStoreCoordinator

    And a warning, this notification comes in on all different threads so you be careful with concurrency. Just put a 5 second sleep in the method and you'll see on app launch 3 different threads call it. This is likely why in the example there is a historyQueue with maxOperationCount 1 to handle it.

    Some notifications have NSPersistentHistoryTokenKey in the userInfo not sure why.