Last active
November 29, 2017 20:24
-
-
Save jazzedge/b9b84af376b12f7f681a93e40a9db344 to your computer and use it in GitHub Desktop.
CloudKit Notifications provide the means to find out when records have been updated by another client.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| See: https://www.whatmatrix.com/blog/a-guide-to-cloudkit-how-to-sync-user-data-across-ios-devices/ | |
| CloudKit Notifications provide the means to find out when records have been updated by another client. However, network conditions and performance constraints can cause individual notifications to be dropped, or multiple notifications to intentionally coalesce into a single client notification. Since CloudKit’s notifications are built on top of the iOS notification system, you have to be on the lookout for these conditions. | |
| However, CloudKit gives you the tools you need for this. | |
| Rather than relying on individual notifications to give you detailed knowledge of what change an individual notification represents, you use a notification to simply indicate that something has changed, and then you can ask CloudKit what’s changed since the last time you asked. In my example, I do this by using CKFetchRecordZoneChangesOperation and CKServerChangeTokens. Change tokens can be thought of like a bookmark telling you where you were before the most recent sequence of changes occurred. | |
| // Handle receipt of an incoming push notification that something has changed. | |
| private let serverChangeTokenKey = "ckServerChangeToken" | |
| public func handleNotification() { | |
| // Use the ChangeToken to fetch only whatever changes have occurred since the last | |
| // time we asked, since intermediate push notifications might have been dropped. | |
| var changeToken: CKServerChangeToken? = nil | |
| let changeTokenData = UserDefaults.standard.data(forKey: serverChangeTokenKey) | |
| if changeTokenData != nil { | |
| changeToken = NSKeyedUnarchiver.unarchiveObject(with: changeTokenData!) as! CKServerChangeToken? | |
| } | |
| let options = CKFetchRecordZoneChangesOptions() | |
| options.previousServerChangeToken = changeToken | |
| let optionsMap = [zoneID!: options] | |
| let operation = CKFetchRecordZoneChangesOperation(recordZoneIDs: [zoneID!], optionsByRecordZoneID: optionsMap) | |
| operation.fetchAllChanges = true | |
| operation.recordChangedBlock = { record in | |
| self.delegate?.cloudKitNoteRecordChanged(record: record) | |
| } | |
| operation.recordZoneChangeTokensUpdatedBlock = { zoneID, changeToken, data in | |
| guard let changeToken = changeToken else { | |
| return | |
| } | |
| let changeTokenData = NSKeyedArchiver.archivedData(withRootObject: changeToken) | |
| UserDefaults.standard.set(changeTokenData, forKey: self.serverChangeTokenKey) | |
| } | |
| operation.recordZoneFetchCompletionBlock = { zoneID, changeToken, data, more, error in | |
| guard error == nil else { | |
| return | |
| } | |
| guard let changeToken = changeToken else { | |
| return | |
| } | |
| let changeTokenData = NSKeyedArchiver.archivedData(withRootObject: changeToken) | |
| UserDefaults.standard.set(changeTokenData, forKey: self.serverChangeTokenKey) | |
| } | |
| operation.fetchRecordZoneChangesCompletionBlock = { error in | |
| guard error == nil else { | |
| return | |
| } | |
| } | |
| operation.qualityOfService = .utility | |
| let container = CKContainer.default() | |
| let db = container.privateCloudDatabase | |
| db.add(operation) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment