Kai Zheng
Kai Zheng

Reputation: 8120

CoreData + CloudKit only synching after minimizing and reopening app

I am currently making an app that needs it's CoreData storage to be synced via iCloud across devices.

Everything works fine except that it's not synching in real-time. (Or at least somewhat close to that). It's not syncing at all when I am doing nothing on Device2 after Device1 changed something. In fact, I have to minimize and reopen the app on Device2 to get the synching working.

This demonstrates it very well: (source)

Here would be a snippet of my code:

let container: NSPersistentCloudKitContainer
var context: NSManagedObjectContext { container.viewContext }

init() {
    container = NSPersistentCloudKitContainer(name: "__Decision")
    
    guard let description = container.persistentStoreDescriptions.first else { ... }
    description.setOption(true as NSObject, forKey:
        NSPersistentStoreRemoteChangeNotificationPostOptionKey)
    
    container.loadPersistentStores(completionHandler: { ... })
    
    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    
    NotificationCenter.default.addObserver(self, selector: #selector(self.processUpdate), name: .NSPersistentStoreRemoteChange, object: nil)
}


@objc func processUpdate(notification: NSNotification) {
    operationQueue.addOperation {
        DispatchQueue.main.async { ... } //Fetch new synched data and update UI 
    }
}
    
    
lazy var operationQueue: OperationQueue = {
    var queue = OperationQueue()
    queue.maxConcurrentOperationCount = 1
    return queue
}()

I have followed the documentation by apple and other tutorials, since this is my first project with CloudKit + CoreData.

Everything seems identical to what they have done.. I have no idea and been working on this problem since days.

Thank you!

Upvotes: 6

Views: 1170

Answers (1)

davidev
davidev

Reputation: 8517

I just show you my setup, because I had the same issue once. I am using CloudKit aswell for macOS and iOS syncing and it does work now. The view gets updated with using SwiftUI.

In my AppDelegate I first register for remoteNotification

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    
    application.registerForRemoteNotifications()
    
    return true
}

My persistenContainer does look like yours:

lazy var persistentContainer: NSPersistentCloudKitContainer = {
    let container = NSPersistentCloudKitContainer(name: "name")
    
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    
    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
    
    return container
}()

And then my signing tab, add background modes:

enter image description here

.. and add Push and iCloud

enter image description here

Also, be patient. Sometimes syncing does need several minutes to get updated.

Upvotes: 8

Related Questions