Restart sync when using NSPersistentCloudKitContainer

It's 2024, and it still seems like the only sure way to cleanly restart cloud sync on an app using NSPersistentCloudKitContainer is to uninstall and reinstall the app. No need to describe how bad that solution is...

Am I missing something? Is there a better way to safely trigger such a restart of the sync (even if it means losing unsaved data and overwriting with what's in the cloud - which is what a reinstall does anyway)?

With the following code I'm successfully turning On or Off sync between CoreData and CloudKit. I have iCloudSync saved in UserDefault / @AppStorage and controlled with a toggle switch in my app settings. This line is what turn it off description.cloudKitContainerOptions = nil, I hope it helps.

class CoreDataManager: ObservableObject{
   // Singleton
   static let instance = CoreDataManager()
   private let queue = DispatchQueue(label: "CoreDataManagerQueue")

@AppStorage(UserDefaults.Keys.iCloudSyncKey) private var iCloudSync = false

lazy var context: NSManagedObjectContext = {
return container.viewContext
}()

lazy var container: NSPersistentContainer = {
return setupContainer()
}()

func updateCloudKitContainer() {
    queue.sync {
        container = setupContainer()
    }
}

func setupContainer()->NSPersistentContainer{
    let container = NSPersistentCloudKitContainer(name: "YourCoreDataContainerName")
    
    guard let description = container.persistentStoreDescriptions.first else{
        fatalError("###\(#function): Failed to retrieve a persistent store description.")
    }
    
    description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
    description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    
    if iCloudSync{
        let cloudKitContainerIdentifier = "iCloud.com.example.DatabaseName"
        if description.cloudKitContainerOptions == nil {
            let options = NSPersistentCloudKitContainerOptions(containerIdentifier: cloudKitContainerIdentifier)
            description.cloudKitContainerOptions = options
        }
    }else{
        description.cloudKitContainerOptions = nil
    }
    
    container.loadPersistentStores { (description, error) in
        if let error = error{
            print("Error loading Core Data. \(error)")
        }
    }
    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

    return container
}

func save(){
    do{
        try context.save()
    }catch let error{
        print("Error saving Core Data. \(error.localizedDescription)")
    }
}
}

Thanks for sharing. I will be testing it

Restart sync when using NSPersistentCloudKitContainer
 
 
Q