ios – Greatest observe to synchronize UserDefaults through iCloud


I’ve an app with varied settings and state saved in UserDefaults, and I need to robotically synchronize them throughout a number of gadgets. Nevertheless, each method I’ve tried to date has resulted in dropping the newest settings in some unspecified time in the future. For instance, when a consumer is offline for a couple of minutes, or when one other machine with older UserDefaults information launches and uploads the previous information, inflicting gadgets with newer information to obtain the outdated info.

I’ve tried utilizing Zephyr, a Swift package deal for synchronizing UserDefaults with iCloud, in addition to DefaultsCloudSync, a Swift file from GitHub that serves an analogous goal. I’ve additionally created my very own class primarily based on DefaultsCloudSync, however all makes an attempt have yielded the identical outcomes.

I wish to know the way different apps cope with this subject or if there’s a “good” resolution obtainable. Any strategies or insights could be tremendously appreciated.

Thanks!

That is my customized iCloud service class (not my proudest code):

class iCloudBackupService: NSObject {

class func manualUpload() -> Outcome<Void, Error> {
    do {
        let defaultsDictionary = UserDefaults.customary.dictionaryRepresentation()
        let cloudStore = NSUbiquitousKeyValueStore.default
        for (key, obj) in defaultsDictionary {
            cloudStore.set(obj, forKey: key as String)
        }
        
        // Get the keys that must be eliminated
        let keysToRemove = cloudStore.dictionaryRepresentation.keys.filter { key in
            !defaultsDictionary.keys.accommodates(key)
        }

        // Take away the keys from the dictionary
        for key in keysToRemove {
            cloudStore.removeObject(forKey: key)
        }
        
        cloudStore.synchronize()
        let excludedUserDefaults = UserDefaults()
        excludedUserDefaults.set(Date(), forKey: "cloudBackupLastUpload")
        print("Manually Up to date iCloud")
        NotificationCenter.default.removeObserver(self, title: UserDefaults.didChangeNotification, object: nil);
        UserDefaults.customary.set(Date(), forKey: "icloudLastBackupDate")
        UserDefaults.customary.set("guide", forKey: "icloudLastBackupTrigger")
        NotificationCenter.default.addObserver(self, selector: #selector(self.updateiCloudFromUserDefaults(notification:)), title: UserDefaults.didChangeNotification, object: nil)
        
        return .success(())
    } catch let error {
        return .failure(error)
    }
}

class func manualRestore() -> Outcome<Void, Error> {
    do {
        // Your code to execute if localDate is older than or equal to cloudDate.
        cease()
        let iCloudDictionary = NSUbiquitousKeyValueStore.default.dictionaryRepresentation
        let userDefaults = UserDefaults.customary
        for (key, obj) in iCloudDictionary {
            userDefaults.set(obj, forKey: key as String)
        }
        userDefaults.synchronize()
        let excludedUserDefaults = UserDefaults()
        excludedUserDefaults.set(Date(), forKey: "cloudBackupLastLocalUpdate")
        print("Manually Up to date native UserDefaults")
        if userDefaults.bool(forKey: "iCloudBackup") == true {
            begin()
        }
        return .success(())
    } catch let error {
        return .failure(error)
    }
}



class func begin() {
    // Be aware: NSUbiquitousKeyValueStoreDidChangeExternallyNotification is distributed solely upon a change acquired from iCloud, not when your app (i.e., the identical occasion) units a worth.
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateUserDefaultsFromiCloud(notification:)), title: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateiCloudFromUserDefaults(notification:)), title: UserDefaults.didChangeNotification, object: nil)
    
    print("CloudBackup service began")
    print("Enabled computerized synchronization of NSUserDefaults and iCloud.")
}

@objc class func updateUserDefaultsFromiCloud(notification: NSNotification?) {
    // Forestall loop of notifications by eradicating our observer earlier than updating UserDefaults
    NotificationCenter.default.removeObserver(self, title: UserDefaults.didChangeNotification, object: nil)

    let iCloudDictionary = NSUbiquitousKeyValueStore.default.dictionaryRepresentation
    let userDefaults = UserDefaults.customary

    // Replace UserDefaults with values from iCloud
    for (key, obj) in iCloudDictionary {
        userDefaults.set(obj, forKey: key as String)
    }
    userDefaults.synchronize()

    // Increment iCloud session computerized obtain occasions
    iCloudSessionAutomaticDownloadTimes += 1

    print("iCloudBackupService: Computerized Obtain. Occasions this Session: (iCloudSessionAutomaticDownloadTimes)")

    // Re-enable UserDefaultsDidChangeNotification notifications
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateUserDefaultsFromiCloud(notification:)), title: UserDefaults.didChangeNotification, object: nil)
}


@objc class func updateiCloudFromUserDefaults(notification: NSNotification?) {
    // Take away the observer earlier than including it once more
    
    NotificationCenter.default.removeObserver(self, title: UserDefaults.didChangeNotification, object: nil)
    
    let defaultsDictionary = UserDefaults.customary.dictionaryRepresentation()
    let cloudStore = NSUbiquitousKeyValueStore.default
    var printKey = ""
    var keyIsRemovable = false
    
    
    for (key, obj) in defaultsDictionary {
        cloudStore.set(obj, forKey: key)
        printKey = key
        keyIsRemovable = false
    }

    // Get the keys that must be eliminated
    let keysToRemove = cloudStore.dictionaryRepresentation.keys.filter { key in
        !defaultsDictionary.keys.accommodates(key)
    }

    // Take away the keys from the dictionary
    for key in keysToRemove {
        cloudStore.removeObject(forKey: key)
        printKey = key
        keyIsRemovable = true
    }

    // let iCloud know that new or up to date keys, values are able to be uploaded
    cloudStore.synchronize()

    // Increment iCloud session computerized add occasions
    iCloudSessionAutomaticUploadTimes += 1

    print("iCloudBackupService: Computerized Add. Occasions this Session: (iCloudSessionAutomaticUploadTimes) Present Object: (printKey). KeyIsRemovable: (keyIsRemovable)" )


    // Add the observer once more
    NotificationCenter.default.addObserver(self, selector: #selector(self.updateiCloudFromUserDefaults(notification:)), title: UserDefaults.didChangeNotification, object: nil)
}



class func cease() {
    NotificationCenter.default.removeObserver(self, title: UserDefaults.didChangeNotification, object: nil);
    NotificationCenter.default.removeObserver(self, title: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: nil);
    print("CloudBackup service stopped")
}

deinit {
    NotificationCenter.default.removeObserver(self, title: UserDefaults.didChangeNotification, object: nil);
    NotificationCenter.default.removeObserver(self, title: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: nil);
}

}

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles