如果接收到的值不匹配正确解码字典
Decoding a Dictionary if received value does not match correct
嘿,我有这个 Json 例如:
{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}
模型class:
struct VersionApi: Decodable {
let data: NestedData?
let v: [String:Int?]
enum CodingKeys: String, CodingKey {
case data = "data"
case v = "v"
}
}
尝试解码时收到此错误消息:
debugDescription: "Expected to decode Int but found a string/data
instead.", underlyingError: nil)
我知道这是什么意思,但我不知道解决办法。
我需要一个格式为 Int 的字典:[String:Int?]
。我试着写一个自定义初始化程序:
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decode(NestedData, forKey: .data)
let vID: [String:Any] = try values.decode([String:Any].self, forKey: .v)
v = try values.decode([String:Int?].self, forKey: .v)
}
然后我想通过字典,如果 Any
不是 Int
,我希望它设置为 nil
。但这不起作用,因为没有候选人产生预期的类型:
No 'decode' candidates produce the expected contextual result type
'[String : Any]'
如果值不是 Int,如何将 Int 设置为 nil?
由于 Any
不可解码,所以编译器报错。您可以先创建一个 enum
(从这个 answer)到 decode/encode 动态类型,
enum BiType<L: Codable, R: Codable>: Codable {
case left(L)
case right(R)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let left = try? container.decode(L.self) {
self = .left(left)
} else if let right = try? container.decode(R.self) {
self = .right(right)
} else {
throw DecodingError
.typeMismatch(
BiType<L, R>.self,
.init(codingPath: decoder.codingPath,
debugDescription: "Expected either `\(L.self)` or `\(R.self)`"))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case let .left(left):
try container.encode(left)
case let .right(right):
try container.encode(right)
}
}
}
现在您可以更新 VersionApi
以使用该类型,
struct VersionApi: Decodable {
let data: NestedData?
let v: [String: BiType<String, Int>]
enum CodingKeys: String, CodingKey {
case data = "data"
case v = "v"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decode(NestedData.self, forKey: .data)
v = try values.decode([String: BiType<String, Int>].self, forKey: .v)
}
}
例子
let data = """
{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}
""".data(using: .utf8)!
do {
let v = try JSONDecoder().decode(VersionApi.self, from: data)
v.v.values.forEach({ (type) in
switch type {
case .left(let left):
debugPrint(left)
case .right(let right):
debugPrint(right)
}
})
} catch {
debugPrint(error)
}
输出
1548303671
"invalid"
"invalid"
嘿,我有这个 Json 例如:
{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}
模型class:
struct VersionApi: Decodable {
let data: NestedData?
let v: [String:Int?]
enum CodingKeys: String, CodingKey {
case data = "data"
case v = "v"
}
}
尝试解码时收到此错误消息:
debugDescription: "Expected to decode Int but found a string/data instead.", underlyingError: nil)
我知道这是什么意思,但我不知道解决办法。
我需要一个格式为 Int 的字典:[String:Int?]
。我试着写一个自定义初始化程序:
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decode(NestedData, forKey: .data)
let vID: [String:Any] = try values.decode([String:Any].self, forKey: .v)
v = try values.decode([String:Int?].self, forKey: .v)
}
然后我想通过字典,如果 Any
不是 Int
,我希望它设置为 nil
。但这不起作用,因为没有候选人产生预期的类型:
No 'decode' candidates produce the expected contextual result type '[String : Any]'
如果值不是 Int,如何将 Int 设置为 nil?
由于 Any
不可解码,所以编译器报错。您可以先创建一个 enum
(从这个 answer)到 decode/encode 动态类型,
enum BiType<L: Codable, R: Codable>: Codable {
case left(L)
case right(R)
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let left = try? container.decode(L.self) {
self = .left(left)
} else if let right = try? container.decode(R.self) {
self = .right(right)
} else {
throw DecodingError
.typeMismatch(
BiType<L, R>.self,
.init(codingPath: decoder.codingPath,
debugDescription: "Expected either `\(L.self)` or `\(R.self)`"))
}
}
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case let .left(left):
try container.encode(left)
case let .right(right):
try container.encode(right)
}
}
}
现在您可以更新 VersionApi
以使用该类型,
struct VersionApi: Decodable {
let data: NestedData?
let v: [String: BiType<String, Int>]
enum CodingKeys: String, CodingKey {
case data = "data"
case v = "v"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
data = try values.decode(NestedData.self, forKey: .data)
v = try values.decode([String: BiType<String, Int>].self, forKey: .v)
}
}
例子
let data = """
{"v":{"value1":1548303671,"value2":"invalid","value3":"invalid"}}
""".data(using: .utf8)!
do {
let v = try JSONDecoder().decode(VersionApi.self, from: data)
v.v.values.forEach({ (type) in
switch type {
case .left(let left):
debugPrint(left)
case .right(let right):
debugPrint(right)
}
})
} catch {
debugPrint(error)
}
输出
1548303671 "invalid" "invalid"