跳到主要内容

状态管理

问题

SwiftUI 的状态管理机制有哪些?@State、@Binding、@StateObject、@ObservedObject、@EnvironmentObject、@Observable 分别在什么场景使用?

答案

状态管理全景

@State — 视图私有值类型状态

struct CounterView: View {
@State private var count = 0 // 视图拥有并管理

var body: some View {
Button("Count: \(count)") {
count += 1 // 修改触发 body 重新计算
}
}
}

@Binding — 双向绑定子视图

struct ToggleRow: View {
let title: String
@Binding var isOn: Bool // 不拥有数据,引用父视图的状态

var body: some View {
Toggle(title, isOn: $isOn)
}
}

struct ParentView: View {
@State private var wifiEnabled = true

var body: some View {
ToggleRow(title: "Wi-Fi", isOn: $wifiEnabled) // $ 传递 Binding
}
}

@StateObject vs @ObservedObject

两者都用于观察 ObservableObject,关键区别在于生命周期

class UserViewModel: ObservableObject {
@Published var name = "Alice"
}

struct ParentView: View {
@StateObject var vm = UserViewModel() // ✅ 拥有并创建,一生只创建一次

var body: some View {
ChildView(vm: vm)
}
}

struct ChildView: View {
@ObservedObject var vm: UserViewModel // 只观察,不拥有

var body: some View {
Text(vm.name)
}
}
关键黄金原则
  • 创建对象的地方用 @StateObject
  • 接收对象的地方用 @ObservedObject

如果用 @ObservedObject 创建对象,父视图刷新时会重新创建,丢失状态!

@EnvironmentObject — 跨层级传递

// 在顶层注入
ContentView()
.environmentObject(appSettings)

// 任意子孙 View 直接使用(无需逐层传递)
struct DeepChildView: View {
@EnvironmentObject var settings: AppSettings

var body: some View {
Text(settings.theme)
}
}

@Observable(iOS 17+ 新方案)

使用 @Observable 宏替代 ObservableObject

@Observable
class UserViewModel {
var name = "Alice" // 无需 @Published
var age = 25
}

struct ContentView: View {
// 用 @State 管理(不再需要 @StateObject)
@State private var vm = UserViewModel()

var body: some View {
Text(vm.name) // 只有 name 变化才刷新(精准追踪)
}
}

@Environment — 系统环境值

struct MyView: View {
@Environment(\.colorScheme) var colorScheme // 深色/浅色模式
@Environment(\.horizontalSizeClass) var sizeClass // iPad 适配

var body: some View {
Text("Mode: \(colorScheme == .dark ? "Dark" : "Light")")
}
}

选择指南

场景推荐
视图内简单值类型@State
传值给子视图(双向)@Binding
创建 ViewModel(iOS 13-16)@StateObject
接收 ViewModel(iOS 13-16)@ObservedObject
跨层级传递(iOS 13-16)@EnvironmentObject
ViewModel(iOS 17+)@Observable + @State
系统环境值@Environment

常见面试问题

Q1: @State 的值存储在哪里?

答案:存储在 SwiftUI 框架管理的外部存储中,而非 View struct 本身。View struct 每次 body 重新计算时会重建,但 @State 的值被关联到视图的标识(identity),在视图生命周期内持续存在。

Q2: @Published 和 @Observable 的区别?

答案

  • @Published(ObservableObject):任何 @Published 属性变化都会通知所有观察者刷新
  • @Observable(Observation 框架):SwiftUI 只追踪 body 中实际读取的属性,只有读取的属性变化才触发刷新,性能更好

Q3: @StateObject 和 @State 管理对象的区别?

答案

  • iOS 13-16:@StateObject 管理 ObservableObject
  • iOS 17+:@State 可以直接管理 @Observable 对象(因为 Observation 框架不依赖 Combine)

相关链接