使用Swift Codable提取JSON数组中混合类型数据的方法
解决Swift中Decodable解码混合类型数组的问题
你遇到的问题我之前也碰到过——JSON数组里的元素是String和Double的混合类型,默认的Decodable没法直接处理这种情况,不过咱们通过自定义解码逻辑就能轻松搞定。
首先调整PortfolioData结构体,让它能解析每个子数组里的日期和数值。从你的示例JSON来看,每个子数组的结构是固定的:第一个元素是日期字符串,第二个是Double类型的数值,所以我们可以利用UnkeyedContainer按顺序提取对应类型的值。
修改后的完整结构体代码如下:
struct PortfolioResponseModel: Decodable { var dataset: Dataset struct Dataset: Decodable { var data: [PortfolioData] } } struct PortfolioData: Decodable { let date: String let value: Double // 自定义解码逻辑 init(from decoder: Decoder) throws { // 获取无键容器,用来解析数组元素 var unkeyedContainer = try decoder.unkeyedContainer() // 按顺序解码第一个元素为String(日期),第二个为Double(数值) date = try unkeyedContainer.decode(String.self) value = try unkeyedContainer.decode(Double.self) } }
接下来你就可以正常解码并获取数据了,测试代码可以改成这样:
let myJSONArray = """ { "dataset": { "data": [ [ "2018-01-19", 181.29 ], [ "2018-01-18", 179.8 ], [ "2018-01-17", 177.6 ], [ "2018-01-16", 178.39 ] ] } } """ do { guard let jsonData = myJSONArray.data(using: .utf8) else { print("无法将字符串转换为Data") return } let details2 = try JSONDecoder().decode(PortfolioResponseModel.self, from: jsonData) // 获取第一个元素的日期 if let firstPortfolioItem = details2.dataset.data.first { print("第一个日期:\(firstPortfolioItem.date)") // 输出 "2018-01-19" print("对应数值:\(firstPortfolioItem.value)") // 输出 181.29 } // 遍历所有数据 for item in details2.dataset.data { print("日期:\(item.date),数值:\(item.value)") } } catch { print("解码失败:\(error.localizedDescription)") }
原理说明
UnkeyedContainer是Decodable专门用来处理数组这类无键集合的容器,我们可以通过它按顺序逐个解码数组里的元素,刚好匹配JSON里子数组的固定顺序(日期在前,数值在后)。如果你的JSON偶尔会出现类型不一致的情况,还可以在解码时添加容错处理(比如用try?尝试解码,或者自定义错误类型),不过从你的示例来看,结构是规范的,上面的代码完全够用。
内容的提问来源于stack exchange,提问作者Mehul Parmar
相关产品推荐
相关产品推荐

