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

继承Codable时子类属性无法赋值问题求助(附示例代码)

解决Swift Codable子类属性无法被编码/解码的问题

这个问题我之前也碰到过,核心原因是Swift的Codable协议在继承场景下的自动合成规则容易被忽略:当子类继承自一个已经遵循Codable的父类时,编译器不会自动为子类合成包含自身属性的Codable实现逻辑。所以你对Secondary实例进行编解码时,只会执行父类Primary的Codable逻辑,完全跳过了子类的b属性,导致它始终保持默认值0。

解决方案一:显式让子类遵循Codable协议

最简单的修复方式就是给Secondary显式添加Codable协议声明,这样编译器会自动为子类合成包含自身属性b的编解码代码,同时会自动调用父类的相关方法:

class Primary : Codable { var a: Int = 0 }
class Secondary : Primary, Codable { var b: Int = 0 }

解决方案二:手动实现Codable方法(自定义场景)

如果需要对编解码逻辑进行自定义(比如处理可选值、重命名字段等),可以手动实现init(from:)和encode(to:)方法,确保同时处理父类和子类的属性:

class Primary : Codable { var a: Int = 0 }

class Secondary : Primary {
    var b: Int = 0
    
    // 定义子类的编码键
    enum CodingKeys: String, CodingKey {
        case b
    }
    
    // 必须实现required的解码初始化方法
    required init(from decoder: Decoder) throws {
        // 先解码子类自己的属性
        let container = try decoder.container(keyedBy: CodingKeys.self)
        b = try container.decode(Int.self, forKey: .b)
        // 再调用父类的解码方法
        try super.init(from: decoder)
    }
    
    // 重写编码方法
    override func encode(to encoder: Encoder) throws {
        // 先编码子类自己的属性
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(b, forKey: .b)
        // 再调用父类的编码方法
        try super.encode(to: encoder)
    }
}

验证测试

你可以在Playground中添加以下代码验证修复效果:

// 创建子类实例并赋值
let secondary = Secondary()
secondary.a = 5
secondary.b = 10

// 编码为JSON
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let data = try encoder.encode(secondary)
print(String(data: data, encoding: .utf8)!)

// 解码回实例
let decoder = JSONDecoder()
let decodedSecondary = try decoder.decode(Secondary.self, from: data)
print("解码后a的值:\(decodedSecondary.a),解码后b的值:\(decodedSecondary.b)")

执行后你会看到JSON中同时包含a和b的键值对,解码后的实例两个属性都能正确获取到设置的值。

内容的提问来源于stack exchange,提问作者Adrian_H

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:36:08