使用Codable协议时如何实现输入输出JSON Key不同?(name→fullname)
解决Swift Codable中解码与编码字段不一致问题
问题分析
你想要实现:Person结构体的name属性,解码时读取JSON的"name"字段,编码时写入JSON的"fullname"字段,但当前编码输出不符合预期。你的代码存在两个核心问题:
- 解码逻辑错误:自定义的
init(from:)使用了映射为"fullname"的CodingKeys,理论上无法从输入的"name"字段解码出值,你能得到John的输出大概率是因为实际运行时使用了手动创建的Person实例,而非解码结果。 - 变量作用域问题:解码得到的
decodedPerson仅在第一个if let块内有效,后续编码代码无法访问该变量,会导致编译错误或使用其他无效实例。
正确实现方案
以下两种方案都能满足你的需求:
方案一:使用动态字符串Key
无需定义CodingKeys,直接在解码和编码阶段指定对应的JSON字段名:
struct Person: Codable { let name: String init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: StringCodingKey.self) // 解码时读取JSON的"name"字段 self.name = try container.decode(String.self, forKey: StringCodingKey(stringValue: "name")!) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: StringCodingKey.self) // 编码时写入JSON的"fullname"字段 try container.encode(name, forKey: StringCodingKey(stringValue: "fullname")!) } } // 辅助结构体,用于处理动态字符串类型的CodingKey private struct StringCodingKey: CodingKey { let stringValue: String init?(stringValue: String) { self.stringValue = stringValue } let intValue: Int? init?(intValue: Int) { return nil } }
方案二:使用区分解码/编码的CodingKeys
定义包含两个枚举值的CodingKeys,分别对应解码和编码的JSON字段:
struct Person: Codable { let name: String enum CodingKeys: String, CodingKey { case decodeName = "name" // 解码用的字段名 case encodeName = "fullname" // 编码用的字段名 } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .decodeName) } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .encodeName) } }
验证代码
修正变量作用域问题后,用你的测试代码验证:
let jsonString = """ { "name": "John" } """ let jsonDecoder = JSONDecoder() var decodedPerson: Person? if let jsonData = jsonString.data(using: .utf8) { decodedPerson = try? jsonDecoder.decode(Person.self, from: jsonData) } print(decodedPerson?.name ?? "Decoding failed") // 输出: John let jsonEncoder = JSONEncoder() jsonEncoder.outputFormatting = .prettyPrinted if let person = decodedPerson, let encodedData = try? jsonEncoder.encode(person), let encodedString = String(data: encodedData, encoding: .utf8) { print(encodedString) } // 预期输出: // { // "fullname" : "John" // }
内容的提问来源于stack exchange,提问作者János
相关产品推荐
相关产品推荐

