如何使用Swift Codable解码data字段可为字典或数组的JSON
Codable 兼容单字典/数组字段解码方案
前置修正
你当前定义的Data结构体和Foundation框架原生Data类型重名,建议修改为ItemData等不冲突的命名,避免编译异常:
struct ItemData: Codable { let id: Int }
方案1:统一转换为数组存储(推荐)
不管返回的是单个字典还是数组,都统一解析为数组,单个字典自动转为长度为1的数组,业务侧无需额外判断类型:
struct Item: Codable { let data: [ItemData] enum CodingKeys: String, CodingKey { case data } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 优先尝试解析为数组 if let dataArray = try? container.decode([ItemData].self, forKey: .data) { self.data = dataArray return } // 解析数组失败则尝试解析为单个对象,包装为数组 if let singleData = try? container.decode(ItemData.self, forKey: .data) { self.data = [singleData] return } // 都不匹配则抛出解码错误 throw DecodingError.dataCorruptedError( forKey: .data, in: container, debugDescription: "data字段既不是ItemData类型也不是ItemData数组类型" ) } }
方案2:保留单值/数组的类型差异
如果业务需要明确区分返回的是单个值还是数组,可以用枚举包装两种情况:
// 定义兼容单值/数组的枚举类型 enum MultiTypeData: Codable { case single(ItemData) case array([ItemData]) init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let single = try? container.decode(ItemData.self) { self = .single(single) return } if let array = try? container.decode([ItemData].self) { self = .array(array) return } throw DecodingError.dataCorruptedError( in: container, debugDescription: "无法解析为ItemData单值或数组" ) } // 如需支持编码可实现encode方法 func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch self { case .single(let item): try container.encode(item) case .array(let items): try container.encode(items) } } } // Item结构定义 struct Item: Codable { let data: MultiTypeData }
内容的提问来源于stack exchange,提问作者Игорь Сазонов
相关产品推荐
相关产品推荐

