状态管理
@State、@Binding、@ObservedObject。
35 分钟
状态管理
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() }
}
}