I've updated an existing CoreData app to use CloudKit so that it can keep data synchronised across multiple devices (for the same iCloud account).
It works! The data sync's just fine.
But the primary UIViewController's view does not reflect the new data. To see the changes, I have to switch to a different view, then switch back to the primary view which has a refreshData()
call in its viewWillAppear()
function. It then re-reads from the data store and displays all the data (including whatever was updated on some other device.
The UIViewController should be observing the NSPersistentStoreRemoteChange
notification as per the viewDidLoad()
below:
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)
}
But the handler function never gets called:
@objc func handleRemoteChange(notification: Notification) {
print("Handling remote change to data in Collection Controller")
refreshData()
}
That print statement never prints anything, and a breakpoint set there never fires.
I have configured the managed object context to merge changes from parent as required immediately after the NSPersistentCloutKitContainer
is created:
container.viewContext.automaticallyMergesChangesFromParent = true
The application has all the relevant iCloud capabilities and entitlements that I'm aware of after scouring the web (and Stack Overflow) for clues, including:
The Container's persistentStoreDescription has the NSPersistentStoreRemoteChangeNotificationPostOptionKey
option set to 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)
}
Clearly the data is being sync'd OK. It's just the notification that is not working as expected. So the end user doesn't see the new/sync'd data automatically.
How can I get this to work?
I have the same problem, and solved by configuring custom persistent store descriptions before calling 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