Swift中如何正确解析包含不同结构Responsible字段的复杂JSON数据
解决方案
思路判断
你提到的在初始化器中匹配类型赋值的思路是正确的,不过现有代码存在一个核心问题:Any类型不兼容Codable协议,无法直接参与编解码,需要先定义枚举类型承载两种不同的responsible结构。
类型定义修正
首先定义带关联值的枚举表示两种可能的负责人类型:
enum Responsible: Codable { case user(User) case userCategory(UserCategory) // 兜底解码逻辑:如果无法依赖type字段匹配,可以用该逻辑自动尝试两种类型 init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() // 先尝试解码为User类型 if let user = try? container.decode(User.self) { self = .user(user) return } // 尝试解码为UserCategory类型 if let category = try? container.decode(UserCategory.self) { self = .userCategory(category) return } // 都匹配失败抛出解码错误 throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Responsible字段无法匹配已知类型")) } }
然后修改MyJson的responsible类型,同时补充CodingKeys处理下划线命名到驼峰命名的映射,优先推荐结合返回的type字段做精准解码:
struct MyJson: Codable { let id: Int let createdAt: String let updatedAt: String let link: String let type: String let responsible: Responsible enum CodingKeys: String, CodingKey { case id, link, type, responsible case createdAt = "created_at" case updatedAt = "updated_at" } // 结合type字段的精准解码逻辑,效率更高,避免结构重叠导致的误判 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 解码通用字段 id = try container.decode(Int.self, forKey: .id) createdAt = try container.decode(String.self, forKey: .createdAt) updatedAt = try container.decode(String.self, forKey: .updatedAt) link = try container.decode(String.self, forKey: .link) type = try container.decode(String.self, forKey: .type) // 根据type字段匹配对应的responsible类型 switch type { case "u": let user = try container.decode(User.self, forKey: .responsible) responsible = .user(user) case "r": let category = try container.decode(UserCategory.self, forKey: .responsible) responsible = .userCategory(category) default: throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "未知的type类型: \(type)") } } } // 子模型补充CodingKeys处理下划线字段,注意comment可能返回null需要定义为可选类型 struct User: Codable { let id: Int let type, email, phone, comment: String? let firstName, secondName: String enum CodingKeys: String, CodingKey { case id, type, email, phone, comment case firstName = "first_name" case secondName = "second_name" } } struct UserCategory: Codable { let id: Int let name, guardName, createdAt, updatedAt: String enum CodingKeys: String, CodingKey { case id, name case guardName = "guard_name" case createdAt = "created_at" case updatedAt = "updated_at" } }
解码使用示例
直接用JSONDecoder解码整个数组即可:
let decoder = JSONDecoder() do { let result = try decoder.decode([MyJson].self, from: jsonData) // 遍历使用responsible字段 for item in result { switch item.responsible { case .user(let user): print("用户类型负责人:\(user.firstName ?? "")") case .userCategory(let category): print("分类类型负责人:\(category.name)") } } } catch { print("解码失败:\(error)") }
内容的提问来源于stack exchange,提问作者swiftProger
相关产品推荐
相关产品推荐

