如何在 Swift 中支持 array(array,string) 的变量 JSON 字段?

How do I support a variable JSON field of array(array,string) in Swift?

所有。

我正在尝试创建一个结构来保存具有特定结构的 API 调用的内容,但不确定如何编写它。

这是 API 的一个结果,我在为接收结构编码时遇到问题:

"10E": {
  "baseSetSize": 264, 
  "block": "Guilds of Ravnica", 
  "boosterV3": [
    [
      "rare", 
      "mythic rare"
    ], 
    "uncommon", 
    "uncommon", 
    "uncommon", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "common", 
    "land", 
    "marketing"
  ], 
  "cards": [ ... ]
}

API 将 'boosterV3' 键列为格式 array(array, string)。但是,一些返回的数据包含一个包含 16 个字符串的数组,并且至少有一个包含一个字符串数组作为它的第一个元素。

我试过使用以下结构:

struct MtGSet : Codable {
    let name: String
    let baseSetSize: Int
    let block: String
    let boosterV3: [String]
    let cards: [MtGCard]
}

但是 运行 反对 API 产生这个错误:

[CodingKeys(stringValue: "boosterV3", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], 
debugDescription: "Expected to decode String but found an array instead.", underlyingError: nil))

是否可以在 Swift 中编写一个数据结构,以接受 16 个字符串值或 15 个字符串值和 1 个字符串数组作为 boosterV3 键?

谢谢。

像下面这样尝试。我没有测试我刚刚通过将 JSON 转换为 Swift 创建的。你也可以自己做,这里是https://app.quicktype.io/.


struct MtGSet : Codable {
    let name: String
    let baseSetSize: Int
    let block: String
    let boosterV3: [BoosterV3] // user [] of BoosterV3 instead of string
    let cards: [MtGCard]
}

enum BoosterV3: Codable {
    case string(String)
    case stringArray([String])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode([String].self) {
            self = .stringArray(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(BoosterV3.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for BoosterV3"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let x):
            try container.encode(x)
        case .stringArray(let x):
            try container.encode(x)
        }
    }
}