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

Swift Codable对象使用didSet/willSet不触发问题咨询

核心问题解释

Swift 语言的底层规则决定了:实例完成初始化流程之前,所有对存储属性的赋值操作,都不会触发didSet/willSet这类属性观察器。这个行为和是否使用Codable协议没有直接绑定关系。

你遇到的didSet不触发的原因可以拆成两部分说明:

  1. 首先你代码里的观察器关键字存在拼写错误:Swift 中对应的属性观察器是全小写的didSet,大写写法DidSet不符合语法规范,本身就无法正常完成观察逻辑绑定。
  2. 就算修正拼写,系统自动为Codable协议合成的解码实现,全程都在类的初始化生命周期内完成所有属性的赋值——这个阶段实例本身还没有走完整个初始化流程,哪怕给带观察器的属性赋值,观察逻辑也不会被执行。

补充边界常识:哪怕是你自己手写的普通类初始化方法,在方法内部给带didSet的存储属性赋值,同样不会触发观察器。只有当实例完全初始化完成后,不管是内部还是外部代码对属性发起的赋值操作,才会正常触发对应的观察逻辑。

常用解决方案

  • 自定义实现init(from:)解码方法,调整赋值顺序触发观察器
    按照逻辑改写解码流程:先为所有存储属性完成基础解码赋值,等整个实例的初始化流程走完,再对带观察器的属性做二次赋值,这个二次赋值的动作就会正常触发didSet。参考实现:
    required public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 基础属性赋值(此阶段处于初始化流程中,赋值不会触发观察器)
        name = try container.decode(String.self, forKey: .name)
        lastname = try container.decodeIfPresent(String.self, forKey: .lastname)
        let decodedAge = try container.decodeIfPresent(Int.self, forKey: .age)
        
        // 完成所有基础属性赋值后,对age的赋值将正常触发didSet
        age = decodedAge
    }
    
  • 抽离观察逻辑为独立方法,在解码完成后显式调用
    把原本计划写在didSet里的业务逻辑封装成独立函数,在JSONDecoder完成解码、拿到实例后,直接调用该函数传入初始的属性值执行对应逻辑,不依赖属性观察器的自动触发。
  • 注意使用场景差异:如果是实例创建完成之后,外部代码直接修改属性(比如objTest.age = 25),这种场景下的didSet是可以正常触发的,不会存在兼容问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.27 13:06:04