一、四句话(所有权模型一句话版)
- @State
👉 “这个值的所有权在 View 自己,生命周期由 SwiftUI 管理。” - @StateObject
👉 “这个引用类型对象由当前 View 创建并拥有,只创建一次。” - @ObservedObject
👉 “这个对象不是我创建的,我只是临时观察它。” - @EnvironmentObject
👉 “这个对象由更高层统一拥有,我只是从环境里拿来用。”
如果你只记住这四句,80% 场景已经不会踩雷。
二、把“所有权”翻译成三个问题(最关键)
每次选属性包装器,只问自己这三件事:
- 是谁创建的?
- 谁负责活多久?
- View 消失时,它要不要跟着消失?
三、完整对照表(所有权 + 生命周期)
| 包装器 | 谁创建 | 谁拥有 | 生命周期绑定 | 典型用途 |
|---|---|---|---|---|
@State | View | SwiftUI State Store | View identity | 简单值类型状态 |
@StateObject | View | View | View identity(一次) | ViewModel / Store |
@ObservedObject | 外部 | 外部 | 外部决定 | 子 View 观察 |
@EnvironmentObject | 根容器 | 全局环境 | App / Scene | 全局共享状态 |
四、最容易混淆的两个(重点)
1️⃣ @StateObject vs @ObservedObject
一句话区别:
谁
init的,谁就用@StateObject;
没init的,就用@ObservedObject。
// 正确
struct ParentView: View {
@StateObject var vm = UserViewModel()
}
// 正确
struct ChildView: View {
@ObservedObject var vm: UserViewModel
}
❌ 错误用法:
@ObservedObject var vm = UserViewModel() // 会被反复创建
2️⃣ @EnvironmentObject 的本质
不是“魔法全局变量”,而是:
由更高层 View 显式注入的依赖
@main
struct App: App {
let session = SessionStore()
var body: some Scene {
WindowGroup {
RootView()
.environmentObject(session)
}
}
}
- View 不负责创建
- View 假定“环境中一定存在”
- 缺失会直接 crash(设计使然)
五、一个超级好记的心智模型(推荐)
把它们当成 资源管理声明:
@State = 我有一个小本子
@StateObject = 我养了一只宠物
@ObservedObject = 我只是帮别人看宠物
@EnvironmentObject= 社区公共设施
六、错误使用的典型后果(速查)
| 错误 | 后果 |
|---|---|
| 用 @ObservedObject 创建对象 | View 重建 → 对象重建 |
| 用 @StateObject 接收外部对象 | 所有权混乱 |
| 滥用 @EnvironmentObject | 隐式依赖难以维护 |
| 用 @State 存引用类型 | 生命周期不可控 |
最终一句话(压轴版)
SwiftUI 的属性包装器不是“状态类型”,而是“所有权声明”:你在告诉系统——这个状态是谁创建的、谁负责活多久。
英文版
6-9. [Architecture Design] @State, @StateObject, @ObservedObject, @EnvironmentObject: How to Explain Their Ownership Models?
I. Four Sentences (The One-Sentence Version of the Ownership Model)
- @State 👉 "The ownership of this value belongs to the View itself; its lifecycle is managed by the SwiftUI State Store."
- @StateObject 👉 "This reference type object is created and owned by the current View; it is initialized only once."
- @ObservedObject 👉 "I did not create this object; I am just observing it temporarily."
- @EnvironmentObject 👉 "This object is owned collectively at a higher level; I am just pulling it from the environment to use it."
If you remember these four sentences, you will avoid 80% of common pitfalls.
II. Translating "Ownership" into Three Key Questions
Whenever choosing a property wrapper, ask yourself these three things:
- Who created it?
- Who is responsible for how long it lives?
- When the View disappears, should this object disappear with it?
III. Complete Comparison Table (Ownership + Lifecycle)
| Wrapper | Creator | Owner | Lifecycle Binding | Typical Use Case |
|---|---|---|---|---|
| @State | View | SwiftUI State Store | View Identity | Simple value-type states |
| @StateObject | View | View | View Identity (created once) | ViewModel / Store |
| @ObservedObject | External | External | Determined by External | Sub-view observation |
| @EnvironmentObject | Root Container | Global Environment | App / Scene | Global shared state |
IV. The Two Most Easily Confused Wrappers
1. @StateObject vs. @ObservedObject
The core distinction:
- If you initialize (init) the object inside the view, use @StateObject.
- If the object is passed in (not initialized by the view), use @ObservedObject.
Swift
// CORRECT
struct ParentView: View {
@StateObject var vm = UserViewModel() // Parent owns it
}
// CORRECT
struct ChildView: View {
@ObservedObject var vm: UserViewModel // Child just observes it
}
❌ Wrong Usage:
@ObservedObject var vm = UserViewModel() // The object will be repeatedly re-created whenever the view updates.
2. The Essence of @EnvironmentObject
It is not a "magical global variable," but rather:
- A dependency explicitly injected by a higher-level View.
- The View is not responsible for creation.
- The View assumes "it must exist in the environment."
- If missing, it will cause a crash (by design).
V. A Super Memorable Mental Model
Treat them as declarations of resource management:
- @State = I have a small notebook.
- @StateObject = I own a pet.
- @ObservedObject = I am just pet-sitting for someone else.
- @EnvironmentObject = Community public facilities.
VI. Typical Consequences of Incorrect Use (Quick Check)
| Error | Consequence |
|---|---|
| Using @ObservedObject to create an object | View rebuild → Object is re-created (State lost) |
| Using @StateObject to receive an external object | Ownership confusion / unexpected persistence |
| Abusing @EnvironmentObject | Implicit dependencies become hard to maintain |
| Using @State for reference types | Uncontrollable lifecycle |
Final Summary
SwiftUI property wrappers are not just "state types"; they are "Ownership Declarations." You are telling the system: who created this state, and who is responsible for its lifespan.