如果接收到的值不匹配,则解码字典正确
Posted
技术标签:
【中文标题】如果接收到的值不匹配,则解码字典正确【英文标题】:Decoding a Dictionary if received value does not match correct 【发布时间】:2019-01-24 09:25:24 【问题描述】:嘿,我有这个 Json 示例:
"v":"value1":1548303671,"value2":"invalid","value3":"invalid"
还有模型类:
struct VersionApi: Decodable
let data: NestedData?
let v: [String:Int?]
enum CodingKeys: String, CodingKey
case data = "data"
case v = "v"
尝试解码时,我收到以下错误消息:
debugDescription: "预期解码 Int 但找到一个字符串/数据 而是。”,基础错误:无)
我知道这意味着什么,但我不知道解决方案。
我需要一本带有这种格式的 Ints 的字典:[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
。但这不起作用,因为没有候选人产生预期的类型:
没有“解码”候选产生预期的上下文结果类型 '[字符串:任意]'
如果值不是 Int,如何将 Int 设置为 nil?
【问题讨论】:
你必须实现可编码的@PaFi 从 Int @PaFi 将其设为字符串 现在它是一个字符串,但它是一个可以存在任何东西的解决方案,例如 nil 也非常好。感谢您的帮助! @abhishek 你是什么意思?结果应该是 Int? Make it String 它可以工作,当你尝试解码它时它看起来像一个 Int 发现它的字符串这就是为什么并尝试实现 Codable 协议,因为你在 struct 中实现的内容是错误的。 【参考方案1】:由于Any
不可解码,因此编译器会抱怨。您可以先创建一个enum
(来自此answer),如下所示对动态类型进行解码/编码,
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"
【讨论】:
没有别的办法,因为有了这个解决方案,我总是不得不为任何进一步的使用而沮丧..?不过谢谢! @PaFi, use someenum
instead of Any
这不起作用,因为Dictionary
具有异构值,因此您不能将其解码为[String:String?]
或[String:Int?]
。如果可以,那么您不应该将v
声明为[String:Any?]
,而是有两个可选属性,一个是[String:String?]
类型,另一个是[String:Int?]
类型,并且始终只分配一个非零值给其中之一。但是,这不是一个简单的情况,因为异构值嵌套在Dictionary
中,因此无法使用JSONDecoder
直接解码。以上是关于如果接收到的值不匹配,则解码字典正确的主要内容,如果未能解决你的问题,请参考以下文章