如何使用 Cloudkit 将字典(或任何其他复杂结构)保存到 iCloud 中?

How to save a dictionary (or any other complex structure) into iCloud using Cloudkit?

我需要将日期绑定到一个值并将其保存到 Cloudkit。与其为每个对象和下标“date”和“value”保存一个新的 CKRecord,我更希望 CKRecord 是一个字典数组:[(date, value)]。我环顾四周,找不到任何此类 Cloudkit 数据存储的示例。我本以为 Codable 会被桥接到 Cloudkit 但我没有看到任何迹象表明这一点。有一个 library 可以处理这个,但它不处理这种类型的嵌套。有办法吗?

尽管 CKRecord 确实能够支持 Array,但它主要用于存储简单的数据类型,例如字符串、数字和 CKRecord.Reference。您没有具体指出您的 'value' 类型是什么,但这是一个使用 JSONEncoder/JSONDecoder 将对 writing/reading 任何可编码类型的支持添加到 CKRecord。 encoder/decoder 只是将 Encodable/Decodable 类型 to/from 转换为二进制 Data 表示,CKRecord 也支持。

private let encoder: JSONEncoder = .init()
private let decoder: JSONDecoder = .init()

extension CKRecord {
    func decode<T>(forKey key: FieldKey) throws -> T where T: Decodable {
        guard let data = self[key] as? Data else {
            throw CocoaError(.coderValueNotFound)
        }
        
        return try decoder.decode(T.self, from: data)
    }
    
    func encode<T>(_ encodable: T, forKey key: FieldKey) throws where T: Encodable {
        self[key] = try encoder.encode(collection)
    }
}

用法如下所示:

let collection: [[Date: String]] = [[:]]
let record = CKRecord(recordType: "MyRecord")
try? record.encode(collection, forKey: "collection")
let persisted = try? record.decode(forKey: "collection") as [[Date: String]]