You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:45:06