swift - 可编码为 CKRecord

标签 swift dictionary cloudkit codable

我有几个可编码的结构,我想创建一个通用协议(protocol)来将它们编码为 CloudKit 的 CKRecord 并解码回来。

我有一个用于创建字典的 Encodable 扩展:

extension Encodable {

    var dictionary: [String: Any] {
        return (try? JSONSerialization.jsonObject(with: JSONEncoder().encode(self), options: .allowFragments)) as? [String: Any] ?? [:]
    }
}

然后在协议(protocol)扩展中,我将记录创建为属性,如果类型是数据,我会尝试创建一个 CKAsset。

var ckEncoded: CKRecord? {

    // Convert self.id to CKRecord.name (CKRecordID)
    guard let idString = self.id?.uuidString else { return nil }
    let record = CKRecord(recordType: Self.entityType.rawValue,
                          recordID: CKRecordID(recordName: idString))

    self.dictionary.forEach {

        if let data = $0.value as? Data {
            if let asset: CKAsset = try? ckAsset(from: data, id: idString) { record[$0.key] = asset }
        } else {
            record[$0.key] = $0.value as? CKRecordValue
        }
    }

    return record
}

解码:

func decode(_ ckRecord: CKRecord) throws {

    let keyIntersection = Set(self.dtoEncoded.dictionary.keys).intersection(ckRecord.allKeys())
    var dictionary: [String: Any?] = [:]

    keyIntersection.forEach {

        if let asset = ckRecord[$0] as? CKAsset {
            dictionary[$0] = try? self.data(from: asset)
        } else {
            dictionary[$0] = ckRecord[$0]
        }
    }

    guard let data = try? JSONSerialization.data(withJSONObject: dictionary) else { throw Errors.LocalData.isCorrupted }
    guard let dto = try? JSONDecoder().decode(self.DTO, from: data) else { throw  Errors.LocalData.isCorrupted }


    do { try decode(dto) }
    catch { throw error }
} 

除数据类型外,一切都来回运作。字典里查不出来。所以,我无法将其转换为 CKAsset。提前谢谢你。

最佳答案

我还发现到目前为止,Apple 还没有对此提供明确的支持。

我的解决方案是手动编码/解码:在我的 Codable 子类上我添加了两个方法:

/// Returns CKRecord
func ckRecord() -> CKRecord {
    let record = CKRecord(recordType: "MyClassType")
    record["title"] = title as CKRecordValue
    record["color"] = color as CKRecordValue
    return record
}


init(withRecord record: CKRecord) {
    title = record["title"] as? String ?? ""
    color = record["color"] as? String ?? kDefaultColor
}

另一种针对更复杂情况的解决方案是使用一些第 3 方库,我遇到的一个是:https://github.com/insidegui/CloudKitCodable

关于swift - 可编码为 CKRecord,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47948924/

相关文章:

ios - 我不能在 switch 内沮丧吗? ( swift 3)

ios - UiTabBarController 中没有这样的模块 'Cocoa'

ios - 无法将排序的字典序列化为 JSON - Swift 3

Python 属性错误 : 'dict' object has no attribute 'append'

ios - 如何重命名 iCloud 容器?

ios - ScrollView 和分段 Controller

swift - Swift 4 中是否可以从父类修改子类的属性?

ios - 当数组中有多个字典时,如何按升序创建数组

ios - CloudKit CKModifyRecordsOperation 给我一个 "Protection data didn' t 匹配”

ios - CloudKit复合查询(OR查询)