【问题标题】:Swift, How to Parse/Decode the JSON using Decodable and Codable, When key are unknow/dynamicSwift,如何使用 Codable 和 Codable 解析/解码 JSON,当密钥未知/动态时
【发布时间】:2019-03-03 01:08:53
【问题描述】:

以下是我的 JSON,我无法解码(使用 CodingKeys) regions 键中的数据是一个字典(“IN-WB”、“IN-DL”等....),因为键是动态的,它可以或多或少地改变.

请帮助我使用 Decodable 和 Codable 解析相同的内容。

所有数据都应该在单个模型中。

{ "provider_code": "AIIN", "name": "Jio 印度", “地区”:[ { “IN-WB”:“西孟加拉邦” }, { “IN-DL”:“德里 NCR” }, { “IN-TN”:“泰米尔纳德邦” }, { “在印度” } ] }

【问题讨论】:

  • 您对 JSON 负责吗?考虑到一个字典数组分别只包含一个键值对是一个非常低效的模型。最好发送像{ "code" : "IN-WB", "name" : "West Bengal"} 这样的字典,顺便解决你的问题。
  • 您所说的“所有数据都应该在单个模型中”是什么意思。 ?)

标签: json swift parsing codable decodable


【解决方案1】:

只需对地区使用字典。

struct Locations: Codable {
    let providerCode: String
    let name: String
    let regions: [[String: String]]

    enum CodingKeys: String, CodingKey {
        case providerCode = "provider_code"
        case name, regions
    }
}

您无法为区域创建特定模型,因为您不知道属性名称

【讨论】:

  • 但是你可以创建 Region(id, name)。为什么不呢,通过 decoder.unkeyedContainer() 或动态键。
  • 您不知道 JSON 密钥?所以 JSONDecoder 将无法做到这一点,您需要覆盖 init(decoder:_) 以解析为 [[String: String]],循环找到的每个项目并初始化一个区域,如 Region(key, value)
【解决方案2】:

一种可能的方法,不使用字典。但我们仍然必须首先找到关键)

我喜欢这种风格,因为我们可以从一开始就使用区域。

// example data.
let string = "{\"provider_code\":\"AIIN\",\"name\":\"Jio India\",\"regions\":[{\"IN-WB\":\"West Bengal\"},{\"IN-DL\":\"Delhi NCR\"},{\"IN-TN\":\"Tamil Nadu\"},{\"IN\":\"India\"}]}"
let data   = string.data(using: .utf8)!

// little helper
struct DynamicGlobalKey: CodingKey {
    var stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int? { return nil }
    init?(intValue: Int) { return nil }
}

// model
struct Location: Decodable {
    let providerCode: String
    let name: String
    let regions: [Region]
}

extension Location {
    struct Region: Decodable {
        let key:  String
        let name: String

        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: DynamicGlobalKey.self)
            key  = container.allKeys.first!.stringValue
            name = try container.decode(String.self, forKey: container.allKeys.first!)
        }
    }
}

// example of decoding.
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

let location = try decoder.decode(Location.self, from: data)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-28
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多