如何使用可编码协议使用嵌套词典解码json

时间:2019-09-10 12:49:27

标签: json swift codable

我正在尝试使用可编码协议解码以下json:

let jsonData = """
{
    "request_state": 200,
    "dynamic_value_1": {
        "temperature": {
            "sol":285.1
        }
      },
    "dynamic_value_2": {
        "temperature": {
            "sol":405.1
        }
    }
}
""".data(using: .utf8)!

我创建了一个带有自定义init的对象,以便正确映射json响应。但是我不知道如何映射

public struct Periods: Codable {
    public var innerDict: [String: InnerValue]

    public struct InnerValue: Codable {
        public let temperature: Temperature
    }

    private struct CustomCodingKeys: CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CustomCodingKeys.self)

        self.innerDict = [String: InnerValue]()
        for key in container.allKeys {
            let value = try container.decode(InnerValue.self, forKey: CustomCodingKeys(stringValue: key.stringValue)!)
            self.innerDict[key.stringValue] = value
        }
    }
}

然后,当我尝试使用解码时:

let model = try JSONDecoder().decode(Periods.self, from: jsonData)

我遇到此错误:

▿ 0 : CustomCodingKeys(stringValue: "request_state", intValue: nil)
  - stringValue : "request_state"
  - intValue : nil
  - debugDescription : "Expected to decode Dictionary<String, Any> but found a number instead."
  - underlyingError : nil

任何帮助创建对象的帮助都可能非常有用!

1 个答案:

答案 0 :(得分:1)

您必须考虑request_state的情况并解码Int

public struct Periods: Decodable {
    var requestState = 0
    public var innerDict = [String: InnerValue]()

    public struct InnerValue: Decodable {
        public let temperature: Temperature
    }

    public struct Temperature: Decodable {
        public let sol: Double
    }

    private struct CustomCodingKeys: CodingKey {
        var stringValue: String
        init?(stringValue: String) { self.stringValue = stringValue }
        var intValue: Int?
        init?(intValue: Int) { return nil }
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CustomCodingKeys.self)

        for key in container.allKeys {
            if key.stringValue == "request_state" {
                requestState = try container.decode(Int.self, forKey: key)
            } else {
                let value = try container.decode(InnerValue.self, forKey: key)
                innerDict[key.stringValue] = value
            }
        }
    }
}