Swift中如何根据外层条件解析JSON的嵌套部分
问题:根据外层结构值解析嵌套的JSON结构(Codable实现)
现有方案可处理不同结构类型,但无法根据外层结构中的值解析同一结构的嵌套部分。收到的JSON响应会根据外层的reportType字段值,改变嵌套reportData的结构,示例如下:
{ "reports": [ { "reportType": "advance", "reportData": { "value1": "true" } }, { "reportType": "simple", "reportData": { "value3": "false", "value": "sample" } } ] }
直接用String作为reportData的类型配合Codable解析会失败,需求是:要么将reportData原样存储后续再解析,要么根据reportType的值,对应解析成不同的结构。
我尝试编写了部分代码,但在switch分支中不知道如何处理:
enum ReportTypes: String { case simple, advance } struct Reports: Codable { let reportArray = [Report] } struct Report: Decodable { let reportType: String let reportData: ReportTypes enum CodingKeys: String, CodingKey { case reportType, reportData } init(from decoder: Decoder) { let container = try decoder.container(keyedBy: CodingKeys.self) self.reportType = try container.decode(String.self, forKey: .reportType) switch ReportTypes(rawValue: self.reportType) { case .simple: ??? case .advance: ??? } } }
解决方案
方案一:修改JSON结构(临时可用)
将reportType字段移到reportData内部,这样可以利用常规的多类型Codable解析逻辑。修改后的JSON结构如下:
{ "reports": [ { "reportType": "advance", "reportData": { "reportType": "advance", "value1": "true" } }, { "reportType": "simple", "reportData": { "reportType": "simple", "value3": "false", "value": "sample" } } ] }
这种方式可以正常解析,但依赖后端修改JSON结构,无法修改时不适用。
方案二:自定义Decoder传递外层值(无需修改JSON)
通过自定义init(from decoder:)方法,先解析外层的reportType,再根据该值解析对应的reportData结构,具体实现步骤:
- 定义对应不同
reportType的reportData结构体:
struct AdvanceReportData: Decodable { let value1: String } struct SimpleReportData: Decodable { let value3: String let value: String }
- 定义一个枚举来封装不同类型的
reportData:
enum ReportData { case advance(AdvanceReportData) case simple(SimpleReportData) }
- 让
ReportData遵循Decodable,并在自定义解析中接收外层的reportType:
extension ReportData: Decodable { init(from decoder: Decoder, reportType: ReportTypes) throws { switch reportType { case .advance: let data = try decoder.singleValueContainer().decode(AdvanceReportData.self) self = .advance(data) case .simple: let data = try decoder.singleValueContainer().decode(SimpleReportData.self) self = .simple(data) } } }
- 修改
Report结构体的解析逻辑,传递reportType给ReportData的解析:
struct Report: Decodable { let reportType: ReportTypes let reportData: ReportData enum CodingKeys: String, CodingKey { case reportType, reportData } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解析reportType并转成枚举类型 self.reportType = try container.decode(ReportTypes.self, forKey: .reportType) // 获取reportData对应的解码器容器,传递reportType进行解析 let reportDataDecoder = container.superDecoder(forKey: .reportData) self.reportData = try ReportData(from: reportDataDecoder, reportType: self.reportType) } }
- 最后修正
Reports结构体的定义:
struct Reports: Decodable { let reports: [Report] }
这样就可以直接解析原始的JSON结构,根据外层的reportType自动匹配对应的reportData结构。
内容的提问来源于stack exchange,提问作者Dushyant Deshwal
相关产品推荐
相关产品推荐

