Understanding synching between NSUserDefaults and iCloud

I'm trying to understand a few issues around the timing of how data are backed up to iCloud and then recovered.


My app uses iCloud backup of my NSUserDefaults and it works fine. For instance changes on one device (iPhone) soon appear on another (appleTV). If the user trashes my app for some reason, they can get back in business with all their own settings and preferences by simply trashing the app and re-installing it from the App Store. Cool.


But here's where I'm confused. As soon as the user reinstalls and starts running the app again, I can see in the log file that iCloud is pushing every stored key-value pair to my app one at time, generating a notification with each pair. I didn't anticipate that many notifications when I wrote my code below, but it usually works fine anyway.


I've seen some odd behavior though and I'm wondering about the timing of all this. The new ***** app opens with some assumed defaults that are used if there is no stored value available. Those assumed values end up in the display. As the key-value pairs arrive from iCloud, which I understand might be several minutes later, these defaults get reset in the background and there is then a discrepancy between the display and the desired values. I never really anticipated defaults being altered by anyone other than the user, in the app interface.


I think what I need is a way to delay launching of the app until the iCloud stored values, if they exist, have all arrived.


Does the synching of iCloud stored values (NSUbiquitousKeyValueStore) get synched when the app is installed, or only when the app first runs?

How long are the iCloud data stored after an app is deleted? Forever? An hour? Users usually trash the app (due to a lockup or such) and reinstall within a few minutes, but what if they were to wait a day? Screwed?


Here's the related code in my AppDelegate that makes it happen.


NotificationCenter.default.addObserver(self, selector: #selector(settingsChange), 
name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default)
   
   @objc func settingsChange() {
        var keyStore = NSUbiquitousKeyValueStore.default
        keyStore.synchronize()
        let defaults: UserDefaults = UserDefaults.standard
        for (key, value) in keyStore.dictionaryRepresentation {
           defaults.set(value, forKey: key)
        }
    }


func applicationWillResignActive(_ application: UIApplication)
        var keyStore = NSUbiquitousKeyValueStore.default
        for (key, value) in UserDefaults.standard.dictionaryRepresentation() {
            keyStore.set(value, forKey: key)
            do {
                try "\(key), \(value)".appendLineToURL(fileURL: url as URL)  // Creates a new file if one is not present
//                logSB.info("Writing \(value) for \(key) to file (not Keystore)")
            }
            catch {
                logSB.error("Could not write to local file")
            }
        }
        do {
            result = try String(contentsOf: url as URL, encoding: String.Encoding.utf8)
            //   The next line logs the entire preferences file
            logSB.warning("userDefaults saved to disk")
            //            logSB.warning("There it is: \n\(results)")
        } catch {
            logSB.error("Could not read the defaults file after writing it")
        }
        logSB.verbose("Synchronizing the iCloud defaults file...")
        keyStore.synchronize()

Replies

I believe I've found one answer. The NSUbiquitousKeyValueStore on iCloud is "forever". Once it's been placed there, it will be used by your app on any device the user installs your app onto. Deleting your app from any one device shouldn't trigger deletion from iCloud of your NSUbiquitousKeyValueStore.


Sound right?