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

如何使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)
    }
}

为什么原来的方案不生效?

  1. 计算属性不参与自动编码:Codable的合成方法只会处理存储属性,协议里的计算属性不会被自动加入编码列表。
  2. 自定义encode未处理共享属性:你写的encode方法只编码了testProperty,完全没涉及encryptionkey的逻辑,自然不会被编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 12:46:15