I want allow toggling iCloud sync of a CoreData database on and off. When the user toggles the setting, updateContainer()
is called. Sync works if the app launches with iCould sync enabled. But after iCould was toggled off and back on, sync is not working.
In the spammy CloudKit logs in the console I found two suspicious warnings: CloudKit setup failed because there is another instance of this persistent store actively syncing with CloudKit in this process.
and Told to tear down with reason: Error NSCocoaErrorDomain:134410
Has someone experience on how to achieve this and has an idea what's wrong here?
Here's my PersistenceController.swift
import CoreData
class PersistenceController {
static var shared = PersistenceController()
lazy var container: NSPersistentContainer = {
setupPersistentContainer()
}()
func updateContainer() {
saveContext()
container = setupPersistentContainer()
}
func saveContext() {...}
private func setupPersistentContainer() -> NSPersistentContainer {
// this value is synchronised across devices via NSUbiquitousKeyValueStore in iCloud
let iCloudSyncEnabled = UserDefaults.standard.bool(forKey: iCouldSyncKey)
var persistentContainer = getPersistentContainer(iCloudSync: iCloudSyncEnabled)
guard let description = persistentContainer.persistentStoreDescriptions.first else {
fatalError("Could not get persistentStoreDescription")
}
// Set merge policy
persistentContainer.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
// Enable HistoryTracking: This allows a non-iCloud persistent container to keep track of changes if a user changes their mind and turns it on.
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
if iCloudSyncEnabled {
persistentContainer.viewContext.automaticallyMergesChangesFromParent = true
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
}
persistentContainer.loadPersistentStores { storeDescription, error in
if let error = error as NSError? {
fatalError("Unresolved error \(error)")
}
}
return persistentContainer
}
private func getPersistentContainer(iCloudSync iCloudSyncEnabled: Bool) -> NSPersistentContainer {
let modelName = "Model"
if iCloudSyncEnabled {
print("Using NSPersistentCloudKitContainer")
return NSPersistentCloudKitContainer(name: modelName)
} else {
print("Using NSPersistentContainer")
return NSPersistentContainer(name: modelName)
}
}
}
This approach is partially based on CoreData+CloudKit | On/off iCloud sync toggle