如何解码具有多个在Swift中未命名的列表的JSON

时间:2019-01-22 10:07:17

标签: arrays json swift struct codable

我正在尝试解码JSON字符串,但似乎有多个列表,这些列表没有可用于结构调用的任何名称/键。据我所知(我所掌握的知识很少),此JSON内部有两个列表,我只想要第二个列表。我知道如何解码普通的JSON,但弄清楚如何调用此无密钥列表/数组令人困惑。

我尝试根据自己想要的列表使结构体使用0或1,作为案例名称,但这也不起作用。我真的只是对如何调用未明确命名的东西感到困惑。以下是我的JSON数据和代码。

这是JSON的一小部分:

[{
    "page": 1,
    "pages": 1,
    "per_page": "5000",
    "total": 58
  },
  [{
    "indicator": {
        "id": "NY.GDP.MKTP.CD",
        "value": "GDP (current US$)"
    },
    "country": {
        "id": "US",
        "value": "United States"
    },
    "value": "19390604000000",
    "decimal": "0",
    "date": "2017"
  },
  {
    "indicator": {
        "id": "NY.GDP.MKTP.CD",
        "value": "GDP (current US$)"
    },
    "country": {
        "id": "US",
        "value": "United States"
    },
    "value": "18624475000000",
    "decimal": "0",
    "date": "2016"
  }]
 ]

这是我的Swift代码:

    let url = URL(string:"https://api.worldbank.org/countries/USA/indicators/NY.GDP.MKTP.CD?per_page=5000&format=json")!

    let task = URLSession.shared.dataTask(with: url) {(data,response, error) in
        if let data = data {
            let jsonDecoder = JSONDecoder()
            let countryData = try? jsonDecoder.decode(CountryData.self, from:data)
            print(countryData?.data)
        }
    }
    task.resume()

    struct CountryData: Codable {
         let data: [Country]
         enum CodingKeys: String, CodingKey {
               case data = ""
         }
         init(from decoder: Decoder) throws {
               let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
               self.data = try valueContainer.decode([Country].self, forKey: CodingKeys.data)
         }
   }

    struct Country: Codable {
          let value: String
          let date: String
          let total: String
          enum CodingKeys: String, CodingKey {
                case value = "value"
                case date = "date"
                case total = "total"
          }
          init(from decoder: Decoder) throws {
                let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
                self.value = try valueContainer.decode(String.self, forKey: CodingKeys.value)
                self.date = try valueContainer.decode(String.self, forKey: CodingKeys.date)
                self.total = try valueContainer.decode(String.self, forKey: CodingKeys.total)
          }
    }

    extension URL {
          func withQueries(_ queries: [String: String]) -> URL? {
                var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
                components?.queryItems = queries.compactMap
                    { URLQueryItem(name: $0.0, value: $0.1) }
                return components?.url
          }
    }

我真的只想最终访问日期并将它们放入tableView的数组中,并能够访问以下视图的其余JSON数据。

非常感谢你, 杰克

1 个答案:

答案 0 :(得分:4)

您只需要在手动解码JSON数组时使用decoder.unkeyedContainer()。然后,您可以指定要逐一解码的元素的类型,因为数组的第一个元素和第二个元素不同,因此需要。如果它们相同,则可以使用JSONDecoder.decode([ArrayElementType].self)对其进行解码。

struct CountryData: Decodable {
    struct Indicator: Decodable {
        let id:String
        let value:String
    }

    struct Country: Decodable {
        let id:String
        let value:String
    }

    let indicator:Indicator
    let country:Country
    let value:String
    let decimal:String
    let date:String
}

struct CountryDataResponse: Decodable {
    let countries:[CountryData]

    struct CountryDataRoot: Decodable {
        let page:Int
        let pages:Int
        let per_page:String
        let total:Int
    }

    init(from decoder:Decoder) throws {
        var container = try decoder.unkeyedContainer()
        try container.decode(CountryDataRoot.self)
        countries = try container.decode([CountryData].self)
    }
}

let countries = try JSONDecoder().decode(CountryDataResponse.self, from: yourJson)