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

Swift中为类成员添加@Published属性包装器及Codable报错解决

报错原因

给属性添加@Published后,属性的底层存储类型变为Published<Value>,而非声明时写的原始类型。Swift编译器自动合成Codable协议实现时,无法自动识别@Published包装属性和编解码键的映射关系,因此会抛出类型不符合Encodable/Decodable协议的编译错误。

可行方案

以下两种方案都可以在保留@Published值变更发布能力的前提下,让类正常遵循Codable协议:

方案1:手动实现Codable编解码逻辑

不需要修改属性声明,手动编写Group类的编解码方法,明确指定属性的映射关系即可,代码如下:

class Item: Identifiable, Codable {
    var id = UUID()
    var text = "Hello World!"
}

class Group: Identifiable, Codable {
    var id = UUID()
    @Published var items: [Item] = []
    
    enum CodingKeys: String, CodingKey {
        case id, items
    }
    
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(UUID.self, forKey: .id)
        items = try container.decode([Item].self, forKey: .items)
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(id, forKey: .id)
        try container.encode(items, forKey: .items)
    }
}

var group = Group()
  • 编解码时直接访问items属性本身即可,不需要使用带$前缀的投影值,Swift会自动处理和@Published包装器底层存储的赋值/读取逻辑。
  • 这个方案通用性强,不会影响其他文件的代码逻辑,适合仅个别类需要处理@Published编解码的场景。

方案2:扩展Published使其支持Codable

如果项目中大量存在@Published标记的Codable属性,可以直接给Published类型添加扩展,当它包装的值遵循Codable时,自动实现Codable协议:

extension Published: Codable where Value: Codable {
    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let initialValue = try container.decode(Value.self)
        self.init(initialValue: initialValue)
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(wrappedValue)
    }
}

添加这个扩展后,你最初写的原始代码不需要任何修改就可以直接编译通过,所有@Published标记的、值类型本身遵循Codable的属性,都会自动获得Codable能力,不需要每个类单独写编解码逻辑。

注意事项
  • 不要对带$前缀的投影值(比如$items)做编解码,这个值是Publisher类型,仅用于订阅值变更事件,不支持序列化。
  • 如果你的类继承自其他Codable的父类,手动实现编解码时记得要调用父类的init(from:)和encode(to:)方法,避免父类属性丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:06:27