I have a Codable struct that is used to decode incoming JSON. Unfortunately, sometimes one of its key's value is a string, and sometimes it is a float. I was able to cobble a couple of do/try/catch blocks below to get it to work, but is there a better way to handle this?
struct Project: Codable {
public let version: Float
init(from decoder: Decoder) throws {
var decodedVersion: Float = 1.0
do {
decodedVersion = try values.decode(Float.self, forKey: .version)
} catch {
do {
if let inVersion = try Float(values.decode(String.self, forKey: .version)) {
decodedVersion = inVersion
}
} catch {
throw error
}
}
version = decodedVersion
}
}
答案 0 :(得分:27)
如果在您的JSON中,与密钥相关联的值有时可能为Float
,有时为String
(除了在后端修复此错误),您也可以采用此方法。
让我们说这是你的“搞笑”JSON
let data = """
[
{
"magicField": "one"
},
{
"magicField":1
}
]
""".data(using: .utf8)!
好,我们如何在Swift中优雅地表示这种数据?
struct Element:Decodable {
let magicField: ???
}
我们希望magicField
始终拥有一个值,有时为Float
,有时为String
。
让我们定义这种类型
enum QuantumValue: Decodable {
case float(Float), string(String)
init(from decoder: Decoder) throws {
if let float = try? decoder.singleValueContainer().decode(Float.self) {
self = .float(float)
return
}
if let string = try? decoder.singleValueContainer().decode(String.self) {
self = .string(string)
return
}
throw QuantumError.missingValue
}
enum QuantumError:Error {
case missingValue
}
}
正如您所看到的,QuantumValue
类型的值可以包含Float
或String
。始终为1且正好为1。
我们现在可以定义JSON的常规元素
struct Element:Decodable {
let magicField: QuantumValue
}
就是这样。让我们最终解码JSON。
if let elms = try? JSONDecoder().decode([Element].self, from: data) {
print(elms)
}
[
Element(magicField: QuantumValue.string("one")),
Element(magicField: QuantumValue.float(1.0))
]
switch magicField {
case .string(let text):
println(text)
case .float(let num):
println(num)
}