解码JSON键数组

问题描述

我有以下JSON数据:

{
  "cities": [
    {
      "id": 1,"name": "Paris","country_code": "FR","attractions": [
        "CityHall","Theatre","Port"
      ],"population": 0
    },{
      "id": 2,"name": "Nice","attractions": [
        "CityHall"
      ],{
      "id": 3,"name": "Berlin","country_code": "DE","attractions": [
        "Theatre",{
      "id": 4,"name": "Munich","attractions": [
        "Theatre"
      ],{
      "id": 5,"name": "Amsterdam","country_code": "NL",{
      "id": 6,"name": "Leiden","attractions": [
        "CItyHall","Theatre"
      ],"population": 0
    }
  ]
}

我正在使用对象使用Moya .request(.getCities).map([City].self,atKeyPath: "cities")对其进行解码:

struct City {
  let id: Int
  let name: String
  let countryCode: String
  //let attractions: [Attraction]
  let population: Int
}

extension City: Decodable  {
  enum CodingKeys: String,CodingKey {
    case id = "id"
    case name = "name"
    case countryCode = "countryCode"
    //case attractions = "attractions"
    case population = "population"
  }
  
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    id = try container.decode(Int.self,forKey: .id)
    name = try container.decode(String.self,forKey: .name)
    countryCode = try container.decode(String.self,forKey: .countryCode)
    //attractions = try container.decode([Attraction].self,forKey: .attractions)
    population = try container.decode(Int.self,forKey: .population)
  }
}

简单漂亮,但问题是我无法弄清楚如何将attractions数组放入此处。我将其作为enum,并尝试使用codingPath

获取密钥
enum Attraction: String {
    case CityHall
    case Theatre
    case Port
}

extension Attraction: Decodable  {
  enum CodingKeys: String,CodingKey {

    // confusion mode initiated :) do I use it the same as in struct here?
    case cityHall = "CityHall"
    case theatre = "Theatre"
    case port = "Port"
  }
  
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    
    let attraction = container.codingPath.first!.stringValue // that would get the first key into string but how to deal with enum?
  }
}

此外,如果这样做可以很好地解码attractions,那么City对象是否可以对嵌套的对象/数组进行解码?

解决方法

简单漂亮

不,简单而漂亮

struct Root : Decodable {
    let cities : [City]
}

struct City : Decodable {
  let id: Int
  let name: String
  let countryCode: String
  let atractions: [Attraction] // note the misspelling
  let population: Int
}

enum Attraction: String,Decodable {
    case cityHall = "CityHall",theatre = "Theatre",port = "Port"
}

let data = Data(jsonString.utf8)

do {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let result = try decoder.decode(Root.self,from: data)
    print(result.cities)
} catch {
    print(error)
}