使用Swift Codable从JSON数组中提取数据

Meh*_*mar 3 json swift swift4 codable decodable

我有这样的JSON响应:

在此处输入图片说明

我目前将可解码结构设计如下:

    struct PortfolioResponseModel: Decodable {
    var dataset: Dataset

    struct Dataset: Decodable {
        var data: Array<PortfolioData> //I cannot use [Any] here...

        struct PortfolioData: Decodable {
            //how to extract this data ?
        }
    }
   }
Run Code Online (Sandbox Code Playgroud)

问题是,如何提取数组中的数据,该数组的值可以为Double或String。

这是在操场上进行这项工作的示例字符串:

   let myJSONArray =
   """
   {
   "dataset": {
   "data": [
    [
   "2018-01-19",
   181.29
   ],
   [
   "2018-01-18",
   179.8
   ],
   [
   "2018-01-17",
   177.6
   ],
   [
   "2018-01-16",
   178.39
   ]
   ]
   }
   }
   """
Run Code Online (Sandbox Code Playgroud)

提取数据:

do {
    let details2: PortfolioResponseModel = try JSONDecoder().decode(PortfolioResponseModel.self, from: myJSONArray.data(using: .utf8)!)
    //print(details2) 
    //print(details2.dataset.data[0]) //somehow get "2018-01-19"

} catch {
    print(error)
}
Run Code Online (Sandbox Code Playgroud)

vad*_*ian 5

我不能在这里使用[任何]。

Any解码JSON时不要使用,因为通常您知道内容的类型。

要解码数组,您必须使用unkeyedContainer和依次解码值

struct PortfolioResponseModel: Decodable {
    var dataset: Dataset

    struct Dataset: Decodable {
        var data: [PortfolioData]

        struct PortfolioData: Decodable {
            let date : String
            let value : Double

            init(from decoder: Decoder) throws {
                var container = try decoder.unkeyedContainer()
                date = try container.decode(String.self)
                value = try container.decode(Double.self)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您甚至可以将日期字符串解码为 Date

struct PortfolioData: Decodable {
    let date : Date
    let value : Double

    init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        date = try container.decode(Date.self)
        value = try container.decode(Double.self)
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您将日期格式化程序添加到解码器

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let details2 = try decoder.decode(PortfolioResponseModel.self, from: Data(myJSONArray.utf8))
Run Code Online (Sandbox Code Playgroud)