Swift中使用Codable将JSON字典解析为对象数组的实现
JSON字典转有序数组的Codable解析方案
API返回的JSON数据
{ "someProperty":"someValue", "type":"type1", "values":{ "first":"someValue", "second":"someValue" } }
问题背景
原模型用[String: String]解析values可正常工作,但因为需要保留数据顺序,要改成[Value]数组结构,直接使用目标模型会报错:Expected to decode Array but found a dictionary instead.
解决方案
通过自定义Codable的解码逻辑,手动将字典转成有序数组。Swift 5.1+中,[String: String]解码时会保留JSON原有的键顺序,因此可以安全地将键值对映射为Value对象数组。
修改后的完整代码
struct MyModel: Codable { let someProperty: String let type: SomeType var values: [Value]? // 定义编码键 enum CodingKeys: String, CodingKey { case someProperty, type, values } // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 解析常规字段 someProperty = try container.decode(String.self, forKey: .someProperty) type = try container.decode(SomeType.self, forKey: .type) // 将字典转为Value数组 if let valuesDict = try container.decodeIfPresent([String: String].self, forKey: .values) { values = valuesDict.map { Value(key: $0.key, value: $0.value) } } else { values = nil } } // 可选:如果需要将模型编码回JSON,实现此方法 func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(someProperty, forKey: .someProperty) try container.encode(type, forKey: .type) // 将Value数组转回字典 if let valuesArray = values { let valuesDict = Dictionary(uniqueKeysWithValues: valuesArray.map { ($0.key, $0.value) }) try container.encode(valuesDict, forKey: .values) } } } enum SomeType: String, Codable { case type1, type2 } struct Value: Codable { let key: String let value: String }
关键说明
- 自定义解码:在
init(from:)中,先解析someProperty和type字段,再把values解码为字典,通过map将每个键值对转为Value对象,组成数组。 - 顺序保留:Swift 5.1及更高版本中,
Dictionary解码时会严格遵循JSON中的键顺序,因此转成数组后顺序与原JSON一致。 - 编码支持:如果需要将模型重新编码为JSON,实现
encode(to:)方法,将[Value]数组转回[String: String]字典即可,保证和原API格式兼容。
内容的提问来源于stack exchange,提问作者Nik
相关产品推荐
相关产品推荐

