新的Swift“ Decoder”类听起来像是解析JSON数据的好方法,但是我发现的所有示例都使用众所周知的,定义明确的’struct’来实现。
在我的情况下,我正在查询返回巨大JSON字符串的任意网站,并且我只关心几个(深度嵌套)字段,所以我不想花所有时间定义一个“结构”来获取在他们。
甚至可以通过“解码器”来做到这一点吗?如果是这样,该如何处理?
这个问题似乎是基于对“可分解的东西”如何工作的误解。为方便起见,Decodable愿意在幕后进行一些自动代码生成,以便您 可以 定义结构或结构嵌套,并仅解码整个JSON。但是您 不需要 利用它来解码JSON。
无需为不需要的“字段”定义结构属性。如果JSON字典包含100个键,而您的对应结构仅包含一个属性,则没有问题;该密钥将被获取,没有其他密钥。
关于“深度嵌套”部分,您应该花很多时间来编写简单的嵌套结构,这些结构执行潜水才能到达您真正关心的字典。但是,即使您不想这样做,也可以编写一个实现的init(from:)摘要,然后取出所需的值。
init(from:)
换句话说,如果您认为Decodable 主要 由的实现组成init(from:),并学习编写所需的代码,则将看到可以用几行简单的代码行来解析此JSON。
举例来说,这是一个深层嵌套的信息的JSON草图,在每个层次上我们都忽略了很多额外的信息:
{ "ignore": true, "outer1": { "ignore": true, "outer2": { "ignore": true, "outer3": { "name": "matt", "ignore": true } } } }
我想做的是定义一个非常简单的struct Person,它仅由深层嵌套组成name:
name
struct Person : Decodable { let name : String }
我可以做到的!为此,我自己实现了Decodable,提供了一个“ hoover”的CodingKey采用者结构和的实现init(from:),这样(这看起来像很多工作,但不是,因为AnyCodingKey实现是样板化,复制并粘贴的)从这里开始,init(coder:)实现只是几行易于编写的代码):
init(coder:)
struct Person : Decodable { let name : String struct AnyCodingKey : CodingKey { var stringValue: String var intValue: Int? init(_ codingKey: CodingKey) { self.stringValue = codingKey.stringValue self.intValue = codingKey.intValue } init(stringValue: String) { self.stringValue = stringValue self.intValue = nil } init(intValue: Int) { self.stringValue = String(intValue) self.intValue = intValue } } init(from decoder: Decoder) throws { var con = try! decoder.container(keyedBy: AnyCodingKey.self) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer1")) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer2")) con = try! con.nestedContainer(keyedBy: AnyCodingKey.self, forKey: AnyCodingKey(stringValue:"outer3")) let name = try! con.decode(String.self, forKey: AnyCodingKey(stringValue:"name")) self.name = name } }
当我想深入研究JSON并获取name信息时,这很简单:
let person = try! JSONDecoder().decode(Person.self, from: json)
结果是一个带有namevalue 的Person对象"matt"。注意,我不必添加任何ignore键,也不需要嵌套结构。
"matt"
ignore