I've successfully followed the sample code from Apple: Synchronizing a local store to the cloud to deduplicate entities that are created in the user's private store.
However my app also has a public store that needs deduplication and if I enable the NSPersistentStoreRemoteChangeNotificationPostOptionKey
for both the private and public store then no deduplication will occur in my private store.
This is reproducible every time by not setting NSPersistentStoreRemoteChangeNotificationPostOptionKey
for the public store.
Has anyone else experienced this and has anyone got a solution to get it to work?
Persistence setup code:
private static func makeStoreDescription(for database: Database) -> NSPersistentStoreDescription {
let url: URL
let scope: CKDatabase.Scope
let configuration: String
switch database {
case .private:
url = Self.privateStoreURL
scope = .private
configuration = "Private"
case .public:
url = Self.publicStoreURL
scope = .public
configuration = "Public"
}
let storeDescription = NSPersistentStoreDescription(url: url)
storeDescription.cloudKitContainerOptions = .init(containerIdentifier: Config.cloudKitContainerIdentifier)
storeDescription.cloudKitContainerOptions?.databaseScope = scope
switch database {
case .private:
storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
case .public:
// Uncommented otherwise deduplication doesn't work
// storeDescription.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
// storeDescription.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
break
}
storeDescription.configuration = configuration
return storeDescription
}
private static func makeContainer(inMemory: Bool = false, useIcloud: Bool) -> NSPersistentCloudKitContainer {
let privateStoreDescription = makeStoreDescription(for: .private)
let publicStoreDescription = makeStoreDescription(for: .public)
let container = NSPersistentCloudKitContainer(name: "Name", managedObjectModel: managedObjectModel)
container.persistentStoreDescriptions = [privateStoreDescription, publicStoreDescription]
// Don't save information for future use if running in memory...
if inMemory {
container.persistentStoreDescriptions.forEach { $0.url = URL(fileURLWithPath: "/dev/null") }
}
print("useIcloud:", useIcloud)
if !useIcloud {
container.persistentStoreDescriptions.forEach { $0.cloudKitContainerOptions = nil }
}
container.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
print("Loaded store configuration:", storeDescription.configuration ?? "")
}
#if DEBUG
// Use the container to initialize the development schema.
// Only necessary whenever changes have been made to the schema.
//try! container.initializeCloudKitSchema(options: [])
#endif
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
container.viewContext.transactionAuthor = Self.transactionAuthor
if !inMemory {
do {
try container.viewContext.setQueryGenerationFrom(.current)
} catch {
fatalError("Failed to pin viewContext to the current generation: \(error)")
}
}
return container
}