大家好,我是程序员柏风,AI 最全的 Vibecoding 学习地图 http://coderoadmap.cn 作者。
状态管理
SwiftUI 是数据驱动 UI:状态变化自动触发视图重绘。对照 /roadmaps/swift-ui「状态管理」节点,属性包装器是 SwiftUI 最核心的概念。
学习目标
- 掌握
@State、@Binding的适用场景 - 使用
@StateObject、@ObservedObject管理 ViewModel - 理解
@EnvironmentObject跨层级共享 - 区分
@Published与手动触发更新
核心概念
@State 与 @Binding
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 20) {
Text("计数: \(count)")
.font(.largeTitle)
StepperView(count: $count)
Button("重置") { count = 0 }
}
.padding()
}
}
struct StepperView: View {
@Binding var count: Int
var body: some View {
HStack {
Button("-") { count -= 1 }
Text("\(count)").frame(width: 40)
Button("+") { count += 1 }
}
}
}
@State 由视图拥有数据;$count 产生 Binding 传给子视图。子视图不拥有数据,只读写绑定。
ObservableObject 与 ViewModel
@MainActor
final class LessonListViewModel: ObservableObject {
@Published var lessons: [Lesson] = []
@Published var searchText = ""
var filteredLessons: [Lesson] {
guard !searchText.isEmpty else { return lessons }
return lessons.filter { $0.title.contains(searchText) }
}
func toggleComplete(id: Int) {
guard let i = lessons.firstIndex(where: { $0.id == id }) else { return }
lessons[i].completed.toggle()
}
func loadMockData() {
lessons = [
Lesson(id: 1, title: "状态管理", completed: false),
Lesson(id: 2, title: "导航", completed: true),
]
}
}
struct LessonSearchView: View {
@StateObject private var viewModel = LessonListViewModel()
var body: some View {
VStack {
TextField("搜索课时", text: $viewModel.searchText)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
List(viewModel.filteredLessons) { lesson in
HStack {
Text(lesson.title)
Spacer()
Image(systemName: lesson.completed ? "checkmark.circle.fill" : "circle")
.onTapGesture { viewModel.toggleComplete(id: lesson.id) }
}
}
}
.onAppear { viewModel.loadMockData() }
}
}
@StateObject 创建并持有 ViewModel 生命周期;@ObservedObject 接收外部传入。@Published 变更自动通知视图刷新。
状态层级速查
| 包装器 | 所有权 | 典型用途 |
|---|---|---|
@State | 视图私有 | 开关、计数、临时输入 |
@Binding | 引用父级 | 子组件双向绑定 |
@StateObject | 视图创建持有 | ViewModel 初始化 |
@ObservedObject | 外部注入 | 父视图传入 ViewModel |
@EnvironmentObject | 环境注入 | 全局 Theme、Auth |
与 React/SwiftUI 对照
| SwiftUI | React Hooks | 说明 |
|---|---|---|
@State | useState | 组件本地状态 |
@Binding | 受控组件 value + onChange | 父控子 |
@StateObject | useState(() => new Store()) | 稳定引用 |
@ObservedObject | props 传入 store | 外部 store |
@EnvironmentObject | useContext | 跨层共享 |
@Published | setState / Zustand | 触发重渲染 |
$variable | 回调 + value 合成 Binding | 语法糖 |
React 的 lifting state up 对应 Swift 将 @State 提升到父 View 并通过 @Binding 下发。
练习
- 实现 Todo 项:
@State管理列表,@Binding传给行组件 - 创建
LessonListViewModel,用@StateObject注入视图 - 用
@EnvironmentObject注入AppSettings(如 darkMode) - 对照 react-props-state 画状态流向图
小结
@State 本地、@Binding 双向、ObservableObject 业务状态。 下一课导航与生命周期。见 swift-ui-essentials。