Swift 对表示为数组的对象的可编码支持

Swift Codable support for objects represented as array

我正在尝试对 API 中的数据进行编码和解码,将对象表示为字符串数组,例如:

[
  ["username", "message", "date"],
  ["username", "message", "date"],
  ["username", "message", "date"]
]

这是对应的 Codable 结构:

struct Message: Codable {
    let user: String
    let content: String
    let date: String

    private enum CodingKeys: Int, CodingKey {
        case user = 0
        case content = 1
        case date = 2
    }
}

编码和解码都不起作用;编码显示创建的是 JSON 对象而不是数组:

let msg = Message(user: "foo", content: "content", date: "2019-06-04")

let jsonData   = try! JSONEncoder().encode(msg)
let jsonString = String(data: jsonData, encoding: .utf8)!

最后的字符串是:

{"content":"content","user":"foo","date":"2019-06-04"}

我的目标是获取下面的字符串

["foo", "content", "2019-06-04"]

在结构中使用自定义 encode/decode 方法解决了这个问题,但强制为每个 struct/class.

创建大量样板文件
init(from decoder: Decoder) throws {
    let container = try decoder.singleValueContainer()
    let values = try container.decode([String].self)
    user    = values[CodingKeys.user.rawValue]
    content = values[CodingKeys.content.rawValue]
    date    = values[CodingKeys.date.rawValue]
}

如何为任何对象继续支持这一点?

是的,这是一个奇怪的 API,但这不是我第一次遇到其中的一个,并且用户使用不同的 API 格式不是我在这里寻找的。

而不是 singleValueContainer 使用 unkeyedContainer,它更健壮。如果要将数组项分配给结构成员,则无论如何都必须编写自定义初始化程序

struct Message: Codable {
    let user: String
    let content: String
    let date: String

    init(from decoder: Decoder) throws {
        var arrayContainer = try decoder.unkeyedContainer()
        guard arrayContainer.count == 3 else { throw DecodingError.dataCorruptedError(in: arrayContainer, debugDescription: "The array must contain three items") }
        user = try arrayContainer.decode(String.self)
        content = try arrayContainer.decode(String.self)
        date = try arrayContainer.decode(String.self)           
    }

    func encode(to encoder: Encoder) throws {
        var arrayContainer = encoder.unkeyedContainer()
        try arrayContainer.encode(contentsOf: [user, content, date])
    }
}