如何处理 Swift 中一个键的两种可能类型的解码?
How do I handle decoding two possible types for one key in Swift?
我有一个用于解码传入 JSON 的 Codable 结构。不幸的是,有时它的键值之一是字符串,有时是浮点数。我能够在下面拼凑几个 do/try/catch 块来让它工作,但是有更好的方法来处理这个问题吗?
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
}
}
如果在你的 JSON 中与键关联的值有时是 Float
有时是 String
(除了在后端修复这个错误)你可以按照这种方法.
假设这是你的 "funny" 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))
]
更新(回答 Rob 的评论)
switch magicField {
case .string(let text):
println(text)
case .float(let num):
println(num)
}
我有一个用于解码传入 JSON 的 Codable 结构。不幸的是,有时它的键值之一是字符串,有时是浮点数。我能够在下面拼凑几个 do/try/catch 块来让它工作,但是有更好的方法来处理这个问题吗?
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
}
}
如果在你的 JSON 中与键关联的值有时是 Float
有时是 String
(除了在后端修复这个错误)你可以按照这种方法.
假设这是你的 "funny" 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))
]
更新(回答 Rob 的评论)
switch magicField {
case .string(let text):
println(text)
case .float(let num):
println(num)
}