将CKServerChangeToken保存到Core Data

4 synchronization core-data ios swift cloudkit

我使用CloudKit和Core Data与Swift来同步我的数据.因此,我创建了订阅,在收到通知后,我从云端获取新数据以更新我的核心数据.这是处理此更新的推荐方法.为了获取数据更改,我可以插入一个CKServerChangeToken来获取新的东西.我的问题是如何将令牌保存到Core Data以便以后获取请求?对于CKRecords,有一种方法只保存元数据,但CKServerChangeToken没有这样的东西.有没有人有想法?

最好的问候,Jannik

ric*_*zza 20

CKServerChangeToken是一个不透明的数据对象,它继承自NSObject并符合NSCopying协议,这意味着您可以使用NSKeyedArchiver和NSKeyedUnarchiver将令牌转换为(NS)Data对象.

然后可以将(NS)Data对象存储到任何NSManagedObject上的属性中.或者,您可以将此数据存储在(NS)UserDefaults中.这是实现此目的的一种方法,作为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")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此扩展,您可以从(NS)UserDefaults获取/设置CKServerChangeToken:

let changeToken = UserDefaults.standard.serverChangeToken
UserDefaults.standard.serverChangeToken = `newToken`
Run Code Online (Sandbox Code Playgroud)

正如所指出的,在iOS 12中不推荐使用NSKeyedUn/Archiver调用.这是一个更新的示例.

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")
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)