Skip to content

Instantly share code, notes, and snippets.

@dkasaj
Last active October 5, 2021 08:15
Show Gist options
  • Save dkasaj/a36cf1b0651bfdf8fd74766b064c7d0b to your computer and use it in GitHub Desktop.
Save dkasaj/a36cf1b0651bfdf8fd74766b064c7d0b to your computer and use it in GitHub Desktop.
Class to handle CloudKit server change tokens
import CloudKit
final class ChangeTokenCache {
// MARK: - Zone support
/// Determines a unique UserDefaults key for storing zone change tokens
/// like from CKFetchRecordZoneChangesOperation
private static func userDefaultsKey(_ zoneID: CKRecordZone.ID) -> String {
return "token_" + zoneID.ownerName + zoneID.zoneName
}
/// Persists a zone change token in standard UserDefaults
static func setZoneToken(_ zoneID: CKRecordZone.ID, token: CKServerChangeToken?) {
setToken(userDefaultsKey(zoneID), token: token)
}
/// Fetches a zone change token from standard UserDefaults
static func getZoneToken(_ zoneID: CKRecordZone.ID) -> CKServerChangeToken? {
return getToken(userDefaultsKey(zoneID))
}
/// Clears a zone change token from standard UserDefaults
static func clearZoneToken(_ zoneID: CKRecordZone.ID) {
UserDefaults.standard.removeObject(forKey: userDefaultsKey(zoneID))
}
// MARK: - Database support
/// Determines a unique UserDefaults key for storing database change tokens
/// like from CKFetchDatabaseChangesOperation
private static func userDefaultsKey(_ database: CKDatabase) -> String {
return "token_db\(database.databaseScope.rawValue)"
}
/// Persists a database change token in standard UserDefaults
static func setDatabaseToken(_ database: CKDatabase, token: CKServerChangeToken?) {
setToken(userDefaultsKey(database), token: token)
}
/// Fetches a database change token from standard UserDefaults
static func getDatabaseToken(_ database: CKDatabase) -> CKServerChangeToken? {
return getToken(userDefaultsKey(database))
}
// MARK: - Actual workers
/// Private method that archives a token as data and persists that to UserDefaults
private static func setToken(_ userDefaultsKey: String, token: CKServerChangeToken?) {
if let token = token,
let data = try? NSKeyedArchiver.archivedData(withRootObject: token, requiringSecureCoding: false) {
UserDefaults.standard.set(data, forKey: userDefaultsKey)
} else {
UserDefaults.standard.removeObject(forKey: userDefaultsKey)
}
}
/// Private method that gets data from UserDefaults and unarchives it as a token
private static func getToken(_ userDefaultsKey: String) -> CKServerChangeToken? {
guard let data = UserDefaults.standard.value(forKey: userDefaultsKey) as? Data else { return nil }
var token: CKServerChangeToken?
do {
token = try NSKeyedUnarchiver.unarchivedObject(ofClass: CKServerChangeToken.self, from: data)
} catch {
token = nil
}
return token
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment