【问题标题】:How to serialise JSON with dynamic types如何使用动态类型反序列化 JSON
【发布时间】:2018-09-01 07:33:54
【问题描述】:

我需要序列化以下类型的 JSON 响应。有不同的类型

[{
 "type": "respiration_rate",
 "value": 45
}
{ "type": "blood_pressure",
 "value": { hg: 50 ,mm:120 }
}]

我序列化上层json的类是

class Template: Codable {
   var type: String?
   var value: Double?
   private enum CodingKeys: String, CodingKey {
        case type
        case value
    }
  }

如何序列化value,无论它是双重还是动态对象?

【问题讨论】:

  • 使用 Any? 代替 Double? 并在稍后阶段转换为受尊重的类型(同时使用该值)
  • 使用Any?抛出does not conform to protocol 编译时错误。
  • 我可能会建议您回退到手动解析,以便您可以创建适当类型结构的实例
  • 您是否只有这两个选项,respiration_rate 将有值 Doubleblood_pressure 将有一个对象?

标签: ios json swift object serialization


【解决方案1】:

这是您需要的代码:

class Template: Codable {
    let type: String?
    let value: Value?

    private enum CodingKeys: String, CodingKey {
        case type
        case value
    }

    typealias ValueDictionary = Dictionary<String, Int>
    enum Value: Codable {
        case double(Double)
        case object(ValueDictionary)

        init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            if let x = try? container.decode(Double.self) {
                self = .double(x)
                return
            }
            if let x = try? container.decode(ValueDictionary.self) {
                self = .object(x)
                return
            }
            throw DecodingError.typeMismatch(Value.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ValueUnion"))
        }

        func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            switch self {
            case .double(let x):
                try container.encode(x)
            case .object(let x):
                try container.encode(x)
            }
        }
    }
}

【讨论】:

    【解决方案2】:

    您可以使用带有关联值的枚举而不是类,因为 JSON 格式似乎是异构的。

    enum Value: Decodable {
        case respirationRate(Double)
        case bloodPressure(hg: Double, mm: Double)
    
        private struct BloodPresure: Decodable {
            let hg: Double
            let mm: Double
        }
    
        private enum CodingKeys: String, CodingKey {
            case type
            case value
        }
    
        init(from decoder: Decoder) throws {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            switch try container.decode(String.self, forKey: .type) {
            case "respiration_rate":
                self = try .respirationRate(container.decode(Double.self, forKey: .value))
            case "blood_pressure":
                let details = try container.decode(BloodPresure.self, forKey: .value)
                self = .bloodPressure(hg: details.hg, mm: details.mm)
            case let type: throw DecodingError.dataCorruptedError(forKey: .value, in: container, debugDescription: "Invalid type: \(type)")
            }
        }
    }
    

    解码你的 json 现在很容易:

    let json = """
    [{
    "type": "respiration_rate",
    "value": 45
    },
    { "type": "blood_pressure",
    "value": { "hg": 50 ,"mm":120 }
    }]
    """
    
    do {
        let values = try JSONDecoder().decode([Value].self, from: json.data(using: .utf8)!)
        print(values)
    } catch {
        print(error)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 2012-11-11
      相关资源
      最近更新 更多