共享模型:Observation 与旧状态体系
当多处 UI 依赖同一份业务数据时,观察模型比层层复制数据更自然。
用你的前端经验理解
可以类比可观察 store 和 Context,但 SwiftUI 追踪的是视图实际访问到的可观察属性。
为什么需要它
当列表、详情和统计都展示同一批文章时,复制三份数组会制造同步问题。共享模型让业务数据具有明确所有者,Observation 让读取这些数据的界面参与更新。依赖传递与变化观察是两件事:Environment 可以把依赖送到下层,但它并不替你决定谁创建模型、何时加载数据。
它是怎样工作的
使用 Observation 的模型通常是 @Observable 类型;View 在 body 中读取可观察属性建立依赖。拥有该实例的视图可以用 @State 保持生命周期,需要生成属性绑定时使用 @Bindable。旧系统常见 ObservableObject、@Published、@StateObject 与 @ObservedObject,需要按最低系统版本和项目既有方案选择,不能只靠名称相似直接替换。
把关键概念连起来
现代方案
@Observable 声明可观察引用模型;视图拥有它时可用 @State,子视图需要绑定时用 @Bindable。
环境
@Environment 适合传递较广泛的依赖,但不要把所有局部状态塞进全局环境。
旧项目
ObservableObject + @Published,以及 @StateObject/@ObservedObject 仍会出现在兼容旧系统的项目中。Observation 在 iOS 17、macOS 14 等起可用。
import Observation@Observablefinal class LibraryModel { var titles: [String] = []}// 拥有模型的 View 中:// @State private var model = LibraryModel()- @Observable 让模型属性变化可被追踪;模型实例仍需要明确的所有者,不能每次 body 计算时重新创建。
- 关注使用位置是否读取了变化的属性。Environment 传递实例,@Bindable 在需要时提供属性绑定,职责不同。
用于理解当前概念的代码片段;部分示例需要放入对应工程与作用域,并补齐上下文。
让两个页面共享收藏数量
- 在明确的应用或功能入口创建一个 LibraryModel,把同一实例传给列表和统计页面。
- 列表动作修改模型中的收藏状态,统计页面读取模型计算的数量。避免维护另一份手动更新的 favoriteCount。
- 预览时注入独立模型,填入少量数据,防止预览操作污染真实磁盘或网络。
这里需要你亲自判断
不要混用两套 API 后指望所有属性自动刷新;先看项目最低系统版本和模型定义方式。
做一个小练习
用一个共享阅读清单模型,让列表页和统计页读取同一份数据。
- 画出模型创建位置以及两个消费者,检查有没有意外执行两次初始化。
- 修改一篇文章的收藏状态,确认列表、详情和总数一致。
展开参考思路与验收标准
应只有一个预期的共享实例,统计结果从源数据派生。模型内部某个非可观察引用对象自行变化,不一定产生你期待的更新;需要检查实际观察链,而不是盲目添加 objectWillChange。