Swift Codable для разбора JSON с динамическими c ключами - PullRequest
0 голосов
/ 15 апреля 2020

Я пытаюсь проанализировать приведенный ниже ответ JSON, который имеет несколько динамических c ключей,

{
"Nagaland": {
    "districtData": {
      "Dimapur": {
        "confirmed": 1,
        "lastupdatedtime": "",
        "delta": {
          "confirmed": 0
        }
      }
    }
  },
  "Meghalaya": {
    "districtData": {
      "East Khasi Hills": {
        "confirmed": 1,
        "lastupdatedtime": "",
        "delta": {
          "confirmed": 0
        }
      }
    }
  }
}

Я написал свою структуру Codable, как показано ниже, *

struct IndianStateListModel: Codable {
    // MARK: Properties
    let state: [String: StateData]
}

struct StateData: Codable {
    // MARK: Properties
    var districtData: Inner?

    /// Mapping Key Enum
    private enum CodingKeys: String, CodingKey {
        case districtData
    }
}

struct Inner: Codable {
    // MARK: Properties
    let districts: [String: DistrictData]
}


struct DistrictData: Codable {
    // MARK: Properties
    var confirmed: Int?
    var lastupdatedtime: String?
    var delta: DailyConfirmedData?

    /// Mapping Key Enum
    private enum CodingKeys: String, CodingKey {
        case confirmed, lastupdatedtime, delta
    }
}

struct DailyConfirmedData: Codable {
    // MARK: Properties
    var confirmed: Int?

    /// Mapping Key Enum
    private enum CodingKeys: String, CodingKey {
        case confirmed
    }
}

Это называется как,

let summary = try JSONDecoder().decode(IndianStateListModel.self, from: data)

Но его возвращение nil

PS: связанный вопрос о декодируемом Swift Кодируемый с динамическими c клавишами

Любое решение, было бы здорово, заранее спасибо

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

Основная проблема заключается в том, что IndianStateListModel имеет свойство под названием states. Но такой ключ не появляется в вашем JSON. Я бы предложил разобрать его с singleValueContainer. Например, возможно:

struct States: Decodable {
    typealias StateName = String
    let states: [StateName: Districts]

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        states = try container.decode([StateName: Districts].self)
    }
}

struct Districts: Decodable {
    typealias DistrictName = String
    var districts: [DistrictName: DistrictData]

    enum CodingKeys: String, CodingKey {
        case districts = "districtData"
    }
}

struct DistrictData: Decodable {
    var confirmed: Int
    var lastupdatedtime: String
    var delta: DailyConfirmedData
}

struct DailyConfirmedData: Decodable {
    var confirmed: Int?
}

И

do {
    let result = try JSONDecoder().decode(States.self, from: data)
    print(result)
} catch {
    print(error)
}
1 голос
/ 15 апреля 2020

Модели Codable, которые необходимо использовать для разбора вышеупомянутых JSON data, должны быть похожими,

Модели:

struct StateData: Codable {
    var districtData: [String:DistrictData]?
}

struct DistrictData: Codable {
    var confirmed: Int?
    var lastupdatedtime: String?
    var delta: DailyConfirmedData?
}

struct DailyConfirmedData: Codable {
    var confirmed: Int?
}

Синтаксический анализ:

let summary = try JSONDecoder().decode([String:StateData].self, from: data)

Примечание: Нет необходимости явно создавать enum CodingKeys, если ключи JSON точно соответствуют свойствам типа Codable.

...