Swift 可编码以使用动态键解析 JSON

Swift Codable to parse JSON with dynamic keys

我正在尝试解析下面的 JSON 响应,它有多个动态键,

{
"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

P.S.: 有关可解码的相关问题 Swift Codable with dynamic keys

任何解决方案都很好,提前致谢

Codable 解析上述JSONdata的模型应该是这样的,

型号:

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)

注意: 如果 JSON 键与 Codable 类型的属性完全匹配,则无需显式创建 enum CodingKeys

根本问题是 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)
}