I'm having trouble getting Core Data to sync to CloudKit's public database. Private DB syncing is working fine, however.
In setting up NSPersistentCloudKitContainer
, I'm creating two store descriptions—one each for public and private, using configurations with those names:
guard let description = container.persistentStoreDescriptions.first else {
fatalError("###\(#function): Failed to retrieve persistent store description")
}
let baseUrl = description.url!.deletingLastPathComponent()
let containerIdentifier = description.cloudKitContainerOptions!.containerIdentifier
// MARK: Private store
let privateDescription = NSPersistentStoreDescription(url: baseUrl.appendingPathComponent("private.sqlite"))
let privateOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
privateOptions.databaseScope = .private
privateDescription.cloudKitContainerOptions = privateOptions
privateDescription.configuration = "Private"
privateDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
privateDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
// MARK: Public store
let publicDescription = NSPersistentStoreDescription(url: baseUrl.appendingPathComponent("public.sqlite"))
let publicOptions = NSPersistentCloudKitContainerOptions(containerIdentifier: containerIdentifier)
publicOptions.databaseScope = .public
publicDescription.cloudKitContainerOptions = publicOptions
publicDescription.configuration = "Public"
publicDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
publicDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
container.persistentStoreDescriptions = [privateDescription, publicDescription]
When I save a record that should sync to the public store however (on managedObjectContext.saveIfChanged()
), it only saves in the local device, not in CloudKit, while in console output I see a message about ignoring remote change notification:
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate remoteStoreDidChange:]_block_invoke_2(3048): <NSCloudKitMirroringDelegate: 0x600003c840e0> - Ignoring remote change notification because it's for a different store: <private store identifier> / <public store identifier>
I can't figure out why this would be (the record type only exists in the configuration for the public store), any help greatly appreciated!
I've tried specifically assigning the object to the public store, to double-check, though still get the same debug message and no data stored in CloudKit.
managedObjectContext.assign(forecastRequest, to: managedObjectContext.persistentStoreCoordinator!.persistentStores.first(where: { $0.configurationName == "Public" })!)
It turns out the 'Ignoring remote changes' message was unrelated.
After creating a separate test project and proving to myself that the code itself worked, with a bit more digging I found the real error:
"Invalid Arguments" (12/2016); server message = "Field '___modTime' is not marked sortable"
This was resolved by adding a SORTABLE
index to modifiedTimestamp
in the CloudKit console. I was aware of the need to add QUERYABLE
indices for public models but missed the SORTABLE
.
Data now syncs as expected for my app.