Swift Codable支持以数组表示的对象

时间:2019-06-04 10:15:54

标签: swift rest codable

我正在尝试对来自API的数据进行编码和解码,该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"]

在结构中使用自定义的编码/解码方法可以解决此问题,但必须为每个结构/类创建很多样板。

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,并且用户不是我在这里寻找的其他API格式。

1 个答案:

答案 0 :(得分:0)

它比singleValueContainer使用unkeyedContainer更强大。如果要将数组项分配给struct成员,则无论如何都必须编写一个自定义初始化程序

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])
    }
}