Swift解析JSON时如何根据同层级type参数动态确定body对象类型
Swift 同层级字段动态类型解码实现方案
核心思路是自定义Decodable初始化逻辑,先读取同层级type字段的取值,再按需将body解码为对应强类型结构体,全程使用强类型约束,无需将属性设为可选。
步骤1:定义统一承载Body类型的关联值枚举
由于Swift是强类型语言,body字段需要有明确的类型声明,使用带关联值的枚举可以同时承载两种不同的Body结构体,保留强类型特性:
enum BodyType: Decodable { case one(OneBody) case two(TwoBody) }
步骤2:自定义MyObject的解码逻辑
重写init(from decoder: Decoder)方法,先解码当前层级的type字段,再根据type值选择对应的结构体类型解码body:
struct MyObject: Decodable { let type: String let body: BodyType // 指定当前层级的解码键 enum CodingKeys: String, CodingKey { case type, body } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先解码同层级的type字段 type = try container.decode(String.self, forKey: .type) // 根据type值动态选择body的解码类型 switch type { case "one": body = .one(try container.decode(OneBody.self, forKey: .body)) case "two": body = .two(try container.decode(TwoBody.self, forKey: .body)) default: throw DecodingError.dataCorruptedError( forKey: .type, in: container, debugDescription: "未知的type取值:\(type)" ) } } }
步骤3:保留两个强类型Body结构体定义
无需修改已经定义好的两个强类型结构体,所有属性保持非可选:
struct OneBody: Decodable { let one: Int } struct TwoBody: Decodable { let two: Int let twoData: String }
调用测试
使用修正后的合法JSON(去掉原示例中的省略占位符)进行解码测试:
let sampleData = Data(""" [ { "type": "one", "body": { "one": 1 } }, { "type": "two", "body": { "two": 2, "twoData": "two" } } ] """.utf8) do { let result = try JSONDecoder().decode([MyObject].self, from: sampleData) // 遍历结果时通过switch枚举分支获取对应强类型实例 for item in result { switch item.body { case .one(let oneBody): print("解析到OneBody类型,one字段值:\(oneBody.one)") case .two(let twoBody): print("解析到TwoBody类型,two字段值:\(twoBody.two),twoData字段值:\(twoBody.twoData)") } } } catch { print("解码出错:\(error.localizedDescription)") }
方案说明
- 所有解析后的属性均为非可选强类型,不存在松散的可选值校验问题
- 解码逻辑在
MyObject内部完成,外部调用时和普通Codable解析无差异 - 后续如果新增
type类型,只需要在BodyType枚举新增对应case,同时在switch分支补充解码逻辑即可,扩展性好 - 遇到未定义的
type值会主动抛出解码错误,避免静默解析失败的问题
内容的提问来源于stack exchange,提问作者Frankenstein
相关产品推荐
相关产品推荐

