如何使Codable协议的计算属性在类与结构体中参与编码?
解决方案
你的问题核心是计算属性不会被Codable自动编码,而且自定义的encode方法没有处理协议里的共享属性。下面分两种场景给出可行方案:
场景1:无需自定义encode方法的模型(类/结构体通用)
如果你的模型不需要自定义编码逻辑,直接用Codable合成方法,那么可以通过协议扩展实现自动编码共享属性:
// 定义基础协议 protocol BaseMainRequestable: Codable { } // 定义动态CodingKey,用于处理共享属性的编码键 private struct DynamicCodingKey: CodingKey { let stringValue: String let intValue: Int? init?(stringValue: String) { self.stringValue = stringValue self.intValue = nil } init?(intValue: Int) { self.stringValue = String(intValue) self.intValue = intValue } } extension BaseMainRequestable { // 共享计算属性 var encryptionkey: String? { get { BaseMainRequestHandler.shared.baseMainRequestConfigs?.encryptionkey } set { BaseMainRequestHandler.shared.baseMainRequestConfigs?.encryptionkey = newValue } } // 封装共享属性的编码逻辑 private func encodeSharedProperties(to encoder: Encoder) throws { var container = encoder.container(keyedBy: DynamicCodingKey.self) if let key = encryptionkey { try container.encode(key, forKey: DynamicCodingKey(stringValue: "encryptionkey")!) } } // 辅助协议,用于调用合成的编码方法 private protocol AutoEncodeHelper: Encodable { func performAutoEncode(to encoder: Encoder) throws } // 让所有BaseMainRequestable类型自动遵循辅助协议 extension BaseMainRequestable: AutoEncodeHelper { func performAutoEncode(to encoder: Encoder) throws { // 这里会自动生成合成的编码逻辑 } } // 覆盖默认的encode方法:先编码自身属性,再编码共享属性 func encode(to encoder: Encoder) throws { try performAutoEncode(to: encoder) try encodeSharedProperties(to: encoder) } }
这样,任何遵循BaseMainRequestable的类/结构体,只要不自定义encode方法,都会自动编码自身存储属性+encryptionkey。
场景2:需要自定义encode方法的模型(比如你的TestModel)
如果模型必须自定义编码逻辑,只需在自己的encode方法末尾调用共享属性的编码逻辑即可:
首先在BaseMainRequestable的扩展里封装共享属性编码方法:
extension BaseMainRequestable { // ... 其他代码保持不变 // 对外暴露的共享属性编码方法 func encodeSharedProperties(to encoder: Encoder) throws { var container = encoder.container(keyedBy: DynamicCodingKey.self) if let key = encryptionkey { try container.encode(key, forKey: DynamicCodingKey(stringValue: "encryptionkey")!) } } }
然后修改TestModel的encode方法:
class TestModel: BaseMainRequestable { var testProperty: String? init(testProperty: String) { self.testProperty = testProperty } required init(from decoder: Decoder) throws { fatalError("init(from:) has not been implemented") } enum CodingKeys: CodingKey { case testProperty } func encode(to encoder: Encoder) throws { // 自定义编码自身属性 var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(testProperty, forKey: .testProperty) // 调用协议扩展的共享属性编码方法 try encodeSharedProperties(to: encoder) } }
为什么原来的方案不生效?
- 计算属性不参与自动编码:Codable的合成方法只会处理存储属性,协议里的计算属性不会被自动加入编码列表。
- 自定义encode未处理共享属性:你写的
encode方法只编码了testProperty,完全没涉及encryptionkey的逻辑,自然不会被编码。
内容的提问来源于stack exchange,提问作者Abdul Rehman
相关产品推荐
相关产品推荐

