Syncing key values between devices

I'm trying to move from NSUserDefaults so that the values sync across devices. The value I'm trying to sync is a single bool, to identify if an initial data import has been done.

I'm using the following code


var keyValStore = NSUbiquitousKeyValueStore()

keyValStore.synchronize()
let firstRun: Bool = keyValStore.bool(forKey: "firstRun")
NSLog("First Run: \(firstRun)")
if(!firstRun) {
  keyValStore.set(true, forKey: "firstRun")
  keyValStore.synchronize()
}


If I run the app on my iPhone, it works as expected, the import only works once. If I then run the app on my iPad, it does that import again when it shouldn't, the log shows

First Run: false

Replies

synchronize doesn't actually sync data with iCloud, it only syncs in-memory changes with the data that's stores on disk. Synchronizing data with iCloud might take a few seconds, depending on the conditions of your device. It is possible that your second device sees firstRun = false, because it didn't have enough time to perform the initial sync. Try to subscribe to this notification and make sure that it is getting called: https://developer.apple.com/documentation/foundation/nsubiquitouskeyvaluestore/1412267-didchangeexternallynotification
OK, so I can see that the notification is being fired and the value is being changed but the notification appears to be fired after the initial import is done.

From the notification
Code Block
NSLog("First Run: \(String(describing: notification.userInfo))")


First Run: Optional([AnyHashable("NSUbiquitousKeyValueStoreChangedKeysKey"): <__NSArrayM 0x60000391c450>( firstRun, timeGrouping, imageThumbSize, dbVersion ) , AnyHashable("NSUbiquitousKeyValueStoreChangeReasonKey"): 1])

Launching the application
Code Block
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
appData.moc = persistentContainer.viewContext
NotificationCenter.default.addObserver(self, selector: #selector(onUbiquitousKeyValueStoreDidChangeExternally(notification:)), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default)
performUpdates()
return true
}


and the performUpdates function
Code Block
func performUpdates() {
        let firstRunPref: Bool = prefs.bool(forKey: "firstRun")
        let firstRun: Bool = keyValStore.bool(forKey: "firstRun")
        if(!firstRun) {
            // Check for old prefs, if existing, there is already data in the db
            if(!firstRunPref) {
                // No previous data
                keyValStore.set(true, forKey: "firstRun")
                NSLog("First Run: Yes inital keyval, no prefs, initial import")
            } else {
                // Previous data exists
                keyValStore.set(true, forKey: "firstRun")
                NSLog("First Run: Yes inital keyval, previous prefs, convert")
            }
        } else {
            updates(useKeyVal: true)
            NSLog("First Run: No, update")
        }
    }