Swift的Decodable类如何为属性设置解码别名匹配API返回的JSON字段
解决方案
该需求完全可以实现,Swift 原生 Decodable 协议已内置支持 JSON 字段和自定义属性名的映射能力,无需引入第三方依赖。
原生标准实现(推荐)
通过定义 CodingKeys 枚举指定映射关系,等效于 Kotlin 中的 @SerializedName 注解,写法简洁且兼容性最好:
class Client: Identifiable, Decodable { let id: Int let token: String // 枚举值对应类的属性,rawValue对应JSON返回的字段名 enum CodingKeys: String, CodingKey { case id = "cliente_id" // 将JSON的cliente_id字段映射到id属性 case token // 字段名和属性名一致时无需指定别名 } init(id: Int, token: String) { self.id = id self.token = token } }
你原有基于 Alamofire 的请求代码不需要做任何修改,解码时会自动完成字段匹配。
兼容多别名的实现
如果需要和 Kotlin 中 @SerializedName 的 alternate 参数一样,同时兼容多个JSON字段名映射到同一个属性,可以手动实现解码初始化方法:
class Client: Identifiable, Decodable { let id: Int let token: String enum CodingKeys: String, CodingKey { case token } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) token = try container.decode(String.self, forKey: .token) // 兼容cliente_id和id两个JSON字段 let dynamicContainer = try decoder.container(keyedBy: GenericCodingKey.self) if let clientId = try dynamicContainer.decodeIfPresent(Int.self, forKey: GenericCodingKey(stringValue: "cliente_id")) { id = clientId } else if let fallbackId = try dynamicContainer.decodeIfPresent(Int.self, forKey: GenericCodingKey(stringValue: "id")) { id = fallbackId } else { throw DecodingError.keyNotFound( GenericCodingKey(stringValue: "id"), .init(codingPath: decoder.codingPath, debugDescription: "未找到有效的id字段") ) } } init(id: Int, token: String) { self.id = id self.token = token } } // 通用动态CodingKey实现,用于匹配任意字段名 fileprivate struct GenericCodingKey: CodingKey { var stringValue: String init(stringValue: String) { self.stringValue = stringValue } var intValue: Int? init?(intValue: Int) { nil } }
自定义注解式实现
如果希望使用类似示例中 @NameforDecode 的注解写法,可以通过 Swift 属性包装器自定义实现,不过除非有特殊业务需求,否则更推荐使用原生的 CodingKeys 方案。
内容的提问来源于stack exchange,提问作者Sebastián García Burgos
相关产品推荐
相关产品推荐

