You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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结构,具体实现步骤:

  1. 定义对应不同reportType的reportData结构体:
struct AdvanceReportData: Decodable {
    let value1: String
}

struct SimpleReportData: Decodable {
    let value3: String
    let value: String
}
  1. 定义一个枚举来封装不同类型的reportData:
enum ReportData {
    case advance(AdvanceReportData)
    case simple(SimpleReportData)
}
  1. 让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)
        }
    }
}
  1. 修改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)
    }
}
  1. 最后修正Reports结构体的定义:
struct Reports: Decodable {
    let reports: [Report]
}

这样就可以直接解析原始的JSON结构,根据外层的reportType自动匹配对应的reportData结构。


内容的提问来源于stack exchange,提问作者Dushyant Deshwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 11:15:56