Swift 在 JSON 中没有完整键的情况下将结构编码为数据

Swift encode structs to data without having the full keys in the JSON

出于协议原因,我必须将我的对象转换为 Data。我在网上找到的所有方法都使用JSON,但由于它是Swift-to-Swift,我想知道是否有为此提供的内置机制。

为什么我不喜欢 JSON?它包括完整的密钥名称,在规模上会产生不必要的开销。让我证明我的意思:

struct Address: Codable {
    var city = ""
    var street = ""
}

struct Person: Codable {
    var name = ""
    var adresses = [Address]()
}

let addresses = [Address(city: "NY", street: "123"), Address(city: "LV", street: "456")]

let personA = Person(name: "A", adresses: addresses)

print(personA)

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(personA) {
    print(encoded)
    
    let str = String(data: encoded, encoding: .utf8)
    print(str) //{\"name\":\"A\",\"adresses\":[{\"street\":\"123\",\"city\":\"NY\"},{\"street\":\"456\",\"city\":\"LV\"}]}
    //it includes the complete key nnames in the JSON
}

Swift 是否提供了一种更有效的方式来处理传输的大小?我知道 Protocol Buffers 但这似乎有点矫枉过正

由于您使用的是结构类型,我认为您最好的选择是 Codable。获得更小占用空间的一种方法是通过无键编码应用自定义编码(以及解码)

因此将此添加到 Address

extension Address {
    func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(city)
        try container.encode(street)
    }

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        city = try container.decode(String.self)
        street = try container.decode(String.self)
    }
}

Person

类似
extension Person {
    func encode(to encoder: Encoder) throws {
        var container = encoder.unkeyedContainer()
        try container.encode(name)
        try container.encode(adresses)
    }

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        name = try container.decode(String.self)
        adresses = try container.decode([Address].self)
    }
}

编码您的示例将得到

33 bytes <-- Down from 83 in my test
["A",[["NY","123"],["LV","456"]]]