Swift使用Decodable自定义解析深层嵌套JSON到指定Beer结构体
实现方案
你不需要为外层嵌套层级单独定义结构体,只需要通过自定义 [Beer] 数组类型的解码逻辑,逐层穿透JSON的嵌套层级拿到目标数据即可,完整实现如下:
完整代码
import Foundation // 仅需定义Beer结构体即可 struct Beer: Decodable { let id: Int let name: String let style: String } // 扩展Array类型,当元素为Beer时自定义解码逻辑 extension Array: Decodable where Element == Beer { public init(from decoder: Decoder) throws { // 定义局部CodingKey,仅用于当前解码逻辑,不会对外暴露 struct CodingKeys: CodingKey { var stringValue: String init?(stringValue: String) { self.stringValue = stringValue } var intValue: Int? init?(intValue: Int) { nil } static let response = CodingKeys(stringValue: "response")! static let list = CodingKeys(stringValue: "list")! static let beers = CodingKeys(stringValue: "beers")! static let beer = CodingKeys(stringValue: "beer")! } // 第一层:取根节点下的response容器 let rootContainer = try decoder.container(keyedBy: CodingKeys.self) let responseContainer = try rootContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .response) // 第二层:取response下的list容器 let listContainer = try responseContainer.nestedContainer(keyedBy: CodingKeys.self, forKey: .list) // 第三层:取list下的beers数组容器 var beersArrayContainer = try listContainer.nestedUnkeyedContainer(forKey: .beers) var result = [Beer]() // 遍历数组容器解码每个Beer对象 while !beersArrayContainer.isAtEnd { let itemContainer = try beersArrayContainer.nestedContainer(keyedBy: CodingKeys.self) let beer = try itemContainer.decode(Beer.self, forKey: .beer) result.append(beer) } self = result } }
使用方式
直接对整个JSON数据调用解码方法即可得到Beer数组:
let jsonData: Data = ... // 你的JSON数据 let decoder = JSONDecoder() do { let beers = try decoder.decode([Beer].self, from: jsonData) print(beers) // 得到解析完成的Beer数组 } catch { print("解码失败: \(error)") }
逻辑说明
- 局部定义的
CodingKey仅服务于本次解码逻辑,不需要对外暴露,也不需要单独定义全局结构体 - 多层嵌套的字典结构通过
nestedContainer(keyedBy:forKey:)逐层向下获取容器 - 数组类型的嵌套结构通过
nestedUnkeyedContainer(forKey:)获取无键容器,遍历逐个解码元素 - Beer本身的属性和JSON中
beer对象的字段完全匹配,不需要自定义解码逻辑,使用系统自动合成的实现即可
内容的提问来源于stack exchange,提问作者AlexNica
相关产品推荐
相关产品推荐

