如何使用动态类型序列化 JSON



我需要序列化一些 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是双精度还是动态对象?

以下是您需要的代码:

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

您可以使用具有关联值的枚举而不是类,因为 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)
}

最新更新