Swift中可观察对象为何在变更前而非变更后通知观察者?
问题描述
Swift新的Observation特性提供了
withObservationTracking(_ apply:onChange:)方法,当apply闭包中访问的任一属性被修改时,会执行onChange闭包。但onChange闭包会在属性更新为新值之前执行。即便在Combine框架中,观察者也会通过objectWillChange()在实际变更之前收到通知。为何不在变更之后通知,以便直接访问新值?这样岂不比设置标志在下一帧更新所有依赖项更简便?
这是设计选择,还是存在更优的客观原因?
核心原因
这并非单纯的设计偏好,而是有多个客观技术考量:
支持原子性的变更干预
变更前通知允许观察者在值落地前执行校验、拦截或资源准备逻辑。比如可以对比旧值和待设置的新值,决定是否中止这次变更;或者提前释放旧值关联的资源(如取消网络请求、清理缓存),避免资源泄漏。如果是变更后通知,就完全失去了这种主动干预的机会。规避竞态条件与重复更新
若在变更后通知,当第一个观察者处理时可能再次修改同一属性,进而触发循环通知或竞态问题。而前置通知的模式下,所有观察者只会收到“即将变更”的信号,统一在下一个运行周期(如SwiftUI的渲染周期、UIKit的RunLoop)中同步依赖项更新,确保批量、有序的处理,避免频繁触发不必要的重复更新。适配SwiftUI的批量更新模型
SwiftUI的视图更新机制依赖“状态即将变更”的信号来标记待重绘视图,随后合并所有变更在一次渲染周期中完成。这种前置通知的模式和SwiftUI的更新逻辑天然匹配——提前告知框架需要更新,框架可以合并多个变更请求,大幅提升渲染性能。如果改为变更后通知,可能导致视图多次重复渲染,错过最佳的合并时机。保持生态兼容性
Combine的objectWillChange是较早的官方状态观察API,Observation作为后续推出的特性,需要和现有生态(Combine、SwiftUI)保持行为一致性,降低开发者的学习成本和代码迁移成本。如果贸然改为变更后通知,会打破现有代码的行为预期,引发大量兼容问题。
内容的提问来源于stack exchange,提问作者rayaantaneja

