父类实现Codable时,子类如何正确使用CodingKeys?
Swift继承Codable类时子类CodingKeys的正确使用方式
我完全理解你遇到的困扰——在Swift中处理继承自Codable的子类时,直接定义子类的CodingKeys并不会自动生效,这是因为Codable的自动合成机制不会默认合并父类和子类的编码键。下面我会详细解释原因并给出解决方案。
问题根源
当你在子类中定义自己的CodingKeys枚举时,Swift会自动合成init(from:)方法,但这个自动生成的方法只会处理子类的编码键,不会调用父类的解码逻辑,同时也不会正确关联子类属性的解码。这就是为什么你的testMessage和obj始终为nil的原因。而当你手动实现init(from:)时,相当于你自己接管了解码流程,能同时处理父类和子类的属性。
正确的实现方式
你需要在子类中做两件事:
- 定义子类专属的
CodingKeys,包含子类特有的属性 - 手动实现
init(from:)和encode(to:)方法(如果需要编码功能),确保同时处理父类和子类的属性
修改后的子类代码
public class ResponseWithObjectBean<T: Codable> : ResponseBean { // 定义子类自己的CodingKeys,只包含子类特有的属性 private enum CodingKeys: String, CodingKey { case testMessage case obj } public var testMessage: String? = nil public var obj: T? = nil // 手动实现解码初始化方法 public required init(from decoder: Decoder) throws { // 1. 先解码子类的属性 let container = try decoder.container(keyedBy: CodingKeys.self) testMessage = try container.decodeIfPresent(String.self, forKey: .testMessage) obj = try container.decodeIfPresent(T.self, forKey: .obj) // 2. 调用父类的解码方法,处理父类的属性(intA、intB) try super.init(from: decoder) } // 如果需要编码功能,同样要手动实现这个方法 public override func encode(to encoder: Encoder) throws { // 1. 先让父类编码自己的属性 try super.encode(to: encoder) // 2. 编码子类的属性 var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(testMessage, forKey: .testMessage) try container.encodeIfPresent(obj, forKey: .obj) } }
代码说明
- 子类CodingKeys:只需要包含子类特有的属性(
testMessage、obj),父类的intA、intB由父类自己的CodingKeys处理。 - 解码流程:先解码子类的属性,再调用
super.init(from: decoder)让父类处理它的属性,这样就能保证所有属性都被正确解析。 - 编码流程:先调用父类的
encode(to:)方法,再编码子类的属性,确保编码后的JSON包含所有层级的属性。
现在用你的测试代码进行解码,response.intA、response.intB、response.testMessage和response.obj都会被正确赋值,不会再出现nil的情况。
内容的提问来源于stack exchange,提问作者zuguorui
相关产品推荐
相关产品推荐

