4

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!

Kai Zheng
  • 6,640
  • 7
  • 43
  • 66
  • 1
    I had the exact same issue, even with closing and opening the app. I had a same question. I followed all the instructions again, made sure to setup Remote notifications and it worked. Your code looks fine, might be the setup – davidev Sep 26 '20 at 08:46
  • Hm, then I should do it too, thanks for your help. – Kai Zheng Sep 26 '20 at 11:30
  • Try to call `application.registerForRemoteNotifications()` in your didFinishLaunchingWithOptions and make sure to add PushNotifcations in the Sign tab – davidev Sep 26 '20 at 12:03
  • 1
    If you are setting the NSPersistentStoreDescription to interact with the public database rather than the private database (previous default before iOS 14 I believe) via `description.cloudKitContainerOptions?.databaseScope = .public`, it will only poll for changes from cloudkit every 30 minutes by design (see 10:30 into the WWDC 2020 session video on this topic: developer.apple.com/videos/play/wwdc2020/10650) – professormeowingtons Nov 23 '20 at 07:22

1 Answers1

4

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.

davidev
  • 7,694
  • 5
  • 21
  • 56
  • 2
    Hey, again thank you for helping me out. Somehow it works now!! I don't know about `application.registerForRemoteNotifications()`, but here is what I have done: - cleaned the build folder. - got rid of the app from all my devices. - got rid of the current app iCloud data completely. And then it just worked again... I came to do this because I have made a simple dummy app with the exact same code for CoreData and CloudKit and it worked... ‍♀️ – Kai Zheng Sep 26 '20 at 14:18
  • 1
    You're a lifesaver. These are very important things to check. If I'd seen this days ago you'd have saved days of my time. Thank you! – John Dec 29 '22 at 02:22