简体   繁体   English

具有不同数组类型的 Swift Codable

[英]Swift Codable with Different Array Types

I'm writing a program where I'm parsing JSON data that includes array of arrays, where the nested arrays have different object types (specifically, [[String, String, Int]]).我正在编写一个程序,在其中解析包含数组数组的JSON数据,其中嵌套数组具有不同的对象类型(特别是 [[String, String, Int]])。 For example,例如,

{
"number": 5295,
"bets": [
    [
        "16",
        "83",
        9
    ],
    [
        "75",
        "99",
        4
    ],
    [
        "46",
        "27",
        5
    ]
]
}

I'm trying to use codable to help me parse the data, but when I try something like我正在尝试使用 codable 来帮助我解析数据,但是当我尝试类似

struct OrderBook: Codable {
    let number: Int
    let bets: [Bet]
}

struct Bet: Codable {
    let price: String
    let sale: String
    let quantity: Int
}

it gives me errors saying that它给了我错误说

Expected to decode Dictionary <String, Any> but found an array instead预期解码 Dictionary <String, Any>但找到了一个数组

How do I get around this?我该如何解决这个问题? I can't declare an array of empty type.我不能声明一个空类型的数组。

One solution (assuming you can't change the JSON) is to implement custom decoding logic for Bet .一种解决方案(假设您无法更改 JSON)是为Bet实现自定义解码逻辑。 You can use an unkeyed container (which reads from a JSON array) in order to decode each of the properties in turn (the order in which you call decode(_:) is the order they're expected to appear in the array).您可以使用无键容器(从 JSON 数组中读取)以依次解码每个属性(您调用decode(_:)的顺序是它们在数组中出现的顺序)。

import Foundation

struct OrderBook : Codable {
  let number: Int
  let bets: [Bet]
}

struct Bet : Codable {
  let price: String
  let sale: String
  let quantity: Int

  init(from decoder: Decoder) throws {
    var container = try decoder.unkeyedContainer()
    self.price = try container.decode(String.self)
    self.sale = try container.decode(String.self)
    self.quantity = try container.decode(Int.self)
  } 

  // if you need encoding (if not, make Bet Decodable
  // and remove this method)
  func encode(to encoder: Encoder) throws {
    var container = encoder.unkeyedContainer()
    try container.encode(price)
    try container.encode(sale)
    try container.encode(quantity)
  }
}

Example decoding:示例解码:

let jsonString = """
{ "number": 5295, "bets": [["16","83",9], ["75","99",4], ["46","27",5]] }
"""

let jsonData = Data(jsonString.utf8)

do {
  let decoded = try JSONDecoder().decode(OrderBook.self, from: jsonData)
  print(decoded)
} catch {
  print(error)
}

// OrderBook(number: 5295, bets: [
//   Bet(price: "16", sale: "83", quantity: 9),
//   Bet(price: "75", sale: "99", quantity: 4),
//   Bet(price: "46", sale: "27", quantity: 5)
// ])

It's bad json structure, if you can change it form server, I would suggest: 这是错误的json结构,如果您可以从服务器更改它,我建议:

{
    "number": 5295,
    "bets": [
       {
          "price": "16",
          "sale": "83",
          "quantity": 9
       }
       ....
    ]
}

But if you cannot change that json format, I think you should use the SwiftyJSON library to handle json. 但是,如果您不能更改该json格式,我认为您应该使用SwiftyJSON库处理json。 I hate Codable :) 我讨厌Codable :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM