Swift,如何在密钥不明/动态的情况下使用Decodable和Codable解析/解码JSON

时间:2018-09-27 07:20:13

标签: json swift parsing codable decodable

下面是我的JSON,无法解码(使用CodingKeys) region 键中的数据是一个词典(“ IN-WB”,“ IN-DL”等。。。),因为这些键是动态的,因此可以或多或少地进行更改

请帮助我使用Decodable和Codable解析它们。

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

{
            "provider_code": "AIIN",
            "name": "Jio India",
            "regions": [
                {
                    "IN-WB": "West Bengal"
                },
                {
                    "IN-DL": "Delhi NCR"
                },
                {
                    "IN-TN": "Tamil Nadu"
                },
                {
                    "IN": "India"
                }
            ]
        }

2 个答案:

答案 0 :(得分: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
    }
}

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

答案 1 :(得分:0)

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

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

// 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)