The CKServerChangeToken is an opaque data object that inherits from NSObject and conforms to the NSCopying protocol, which means that you can use a NSKeyedArchiver and NSKeyedUnarchiver to convert the token to an (NS)Data object.
A (NS)Data object can then be stored into a property on any NSManagedObject. Alternatively you could store this data in the (NS)UserDefaults. Here's one way to accomplish this as a swift extension to UserDefaults:
import Foundation
import CloudKit
public extension UserDefaults {
public var serverChangeToken: CKServerChangeToken? {
get {
guard let data = self.value(forKey: "ChangeToken") as? Data else {
return nil
}
guard let token = NSKeyedUnarchiver.unarchiveObject(with: data) as? CKServerChangeToken else {
return nil
}
return token
}
set {
if let token = newValue {
let data = NSKeyedArchiver.archivedData(withRootObject: token)
self.set(data, forKey: "ChangeToken")
} else {
self.removeObject(forKey: "ChangeToken")
}
}
}
}
With this extension you can get/set the CKServerChangeToken right from (NS)UserDefaults with:
let changeToken = UserDefaults.standard.serverChangeToken
UserDefaults.standard.serverChangeToken = `newToken`
As pointed out, the NSKeyedUn/Archiver calls were deprecated in iOS 12. Here is an updated example.
import Foundation
import CloudKit
public extension UserDefaults {
public var serverChangeToken: CKServerChangeToken? {
get {
guard let data = self.value(forKey: "ChangeToken") as? Data else {
return nil
}
let token: CKServerChangeToken?
do {
token = try NSKeyedUnarchiver.unarchivedObject(ofClass: CKServerChangeToken.self, from: data)
} catch {
token = nil
}
return token
}
set {
if let token = newValue {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: token, requiringSecureCoding: false)
self.set(data, forKey: "ChangeToken")
} catch {
// handle error
}
} else {
self.removeObject(forKey: "ChangeToken")
}
}
}
}