如何用单个Decodable结构体解码两种键名不同的同结构JSON响应
可以使用单个Struct完成两种响应的解码
核心思路是自定义Decodable的初始化逻辑,为存在键名差异的属性同时兼容两种键名,优先尝试匹配响应2的键,匹配失败时自动降级尝试匹配响应1的对应键即可。
完整实现代码
struct Verse: Decodable, Identifiable { let id: Int let book_name: String let book_id: Int let verse: String let verse_number: Int let chapter: Int // 数据库中的章节ID let chapter_number: Int // 定义两种响应中所有用到的键名 enum CodingKeys: String, CodingKey { case id, verse, verse_number, chapter case book_name, chapter__book__name case book_id, chapter__book__id case chapter_number, chapter__chapter } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 无差异的字段直接解码 id = try container.decode(Int.self, forKey: .id) verse = try container.decode(String.self, forKey: .verse) verse_number = try container.decode(Int.self, forKey: .verse_number) chapter = try container.decode(Int.self, forKey: .chapter) // 有键名差异的字段优先匹配响应2的键,失败则匹配响应1的键 book_name = try container.decodeIfPresent(String.self, forKey: .book_name) ?? container.decode(String.self, forKey: .chapter__book__name) book_id = try container.decodeIfPresent(Int.self, forKey: .book_id) ?? container.decode(Int.self, forKey: .chapter__book__id) chapter_number = try container.decodeIfPresent(Int.self, forKey: .chapter_number) ?? container.decode(Int.self, forKey: .chapter__chapter) } }
说明
- 上述实现对上层业务完全透明,对外暴露的属性命名和你原来的定义完全一致,不需要修改现有调用逻辑
- 如果后续新增其他键名规则,只需要在CodingKeys中新增对应键,同时在初始化方法中增加对应的降级解码逻辑即可
- 若存在某个字段在两种响应中都可能为空的场景,可将对应属性修改为可选类型(如
let book_name: String?),避免解码失败
内容的提问来源于stack exchange,提问作者erikvm
相关产品推荐
相关产品推荐

