SwiftUI之状态管理全解析
- 互联网
- 2025-09-18 00:39:02

文章目录 引言 一、`@State` 1.1 基本概念 1.2 初始化与默认值 1.3 注意事项 二、`@Binding` 2.1 基本概念 2.2 初始化与使用 2.3 注意事项 三、`@ObservedObject` 3.1 基本概念 3.2 初始化与使用 3.3 注意事项 四、`@EnvironmentObject` 4.1 基本概念 4.2 初始化与使用 4.3 注意事项 五、`@StateObject` 5.1 基本概念 5.2 初始化与使用 5.3 注意事项 六、@ObservedObject、@StateObject、@EnvironmentObject区别及使用场景 6.1 区别 6.1.1 对象创建和所有权 6.1.2 生命周期管理 6.1.3 数据传递方式 6.2 使用场景 6.2.1 `@ObservedObject` 6.2.2 `@StateObject` 6.2.3 `@EnvironmentObject` 七、综合案例 7.1 电商购物案例 7.2 代码解释 7.2.1 数据模型 7.2.2 购物车视图模型(`ShoppingCartViewModel`) 7.2.3 商品单元格视图(`ProductCell`) 7.2.4 商品列表视图(`ProductListView`) 7.2.5 购物车视图(`CartView`) 7.2.6 主视图(`MainView`) 八、小结 引言
在 SwiftUI 中,状态管理是构建交互式和动态用户界面的核心。状态代表着应用程序的数据,当这些数据发生变化时,SwiftUI 会自动更新与之关联的视图,以反映最新的状态。本文将详细介绍 SwiftUI 中几种常见的状态管理方式,包括 @State、@Binding、@ObservedObject、@EnvironmentObject 和 @StateObject,并探讨它们的使用场景、初始化、默认值设置以及注意事项。
一、@State 1.1 基本概念@State 是 SwiftUI 中用于管理视图私有状态的属性包装器。它通常用于存储简单的值,如布尔值、整数、字符串等,并且只能在结构体视图中使用。当 @State 变量的值发生变化时,SwiftUI 会重新计算并更新依赖于该变量的视图部分。
1.2 初始化与默认值@State 变量必须在声明时进行初始化,因为它代表着视图的初始状态。可以为其提供一个默认值,这个默认值将作为视图首次显示时的状态。
import SwiftUI struct StateExampleView: View { // 初始化 @State 变量并设置默认值 @State private var isFavorite = false var body: some View { Button(action: { self.isFavorite.toggle() }) { Text(isFavorite ? "已收藏" : "收藏") } } }在上述代码中,isFavorite 是一个 @State 变量,初始值为 false。当按钮被点击时,isFavorite 的值会取反,视图会相应地更新显示内容。
1.3 注意事项 私有性:@State 变量应该是私有的,因为它是视图的内部状态,不应该被外部视图直接访问或修改。 值类型:@State 通常用于存储值类型(如结构体、枚举),因为值类型的赋值会创建一个新的副本,这有助于 SwiftUI 检测状态的变化。 视图重建:当 @State 变量的值发生变化时,SwiftUI 会重新计算整个视图的 body 属性,因此应避免在 body 中执行昂贵的操作。 二、@Binding 2.1 基本概念@Binding 用于在不同视图之间共享状态,实现双向数据绑定。它允许一个视图修改另一个视图的状态,通常用于将父视图的 @State 变量传递给子视图。
2.2 初始化与使用@Binding 变量不能直接初始化,它必须通过外部传递的 Binding 实例进行赋值。通常在父视图中使用 $ 符号将 @State 变量转换为 Binding 实例,并传递给子视图。
import SwiftUI // 子视图 struct TextFieldView: View { @Binding var text: String var body: some View { TextField("输入文本", text: $text) } } // 父视图 struct BindingExampleView: View { @State private var inputText = "" var body: some View { VStack { // 将 @State 变量转换为 Binding 并传递给子视图 TextFieldView(text: $inputText) Text("你输入的文本是: \(inputText)") } } }在上述代码中,TextFieldView 接收一个 @Binding 变量 text,并将其绑定到 TextField 上。父视图 BindingExampleView 将自己的 @State 变量 inputText 通过 $ 符号转换为 Binding 实例传递给子视图。当用户在 TextField 中输入文本时,父视图中的 inputText 会相应更新。
2.3 注意事项 依赖外部状态:@Binding 变量依赖于外部传递的 Binding 实例,因此必须确保在使用之前已经正确初始化。 数据一致性:由于 @Binding 实现了双向数据绑定,任何对 @Binding 变量的修改都会反映到原始的 @State 变量上,需要注意数据的一致性和正确性。 三、@ObservedObject 3.1 基本概念@ObservedObject 用于观察符合 ObservableObject 协议的对象。当被观察对象的 @Published 属性发生变化时,SwiftUI 会自动更新关联的视图。@ObservedObject 通常用于管理复杂的状态逻辑,将状态和业务逻辑封装在一个独立的对象中。
3.2 初始化与使用@ObservedObject 变量可以在视图中直接初始化,也可以通过外部传递。被观察的对象必须符合 ObservableObject 协议,并且需要使用 @Published 标记需要观察的属性。
import SwiftUI import Combine // 定义一个符合 ObservableObject 协议的类 class CounterViewModel: ObservableObject { // 使用 @Published 标记需要观察的属性 @Published var count = 0 func increment() { count += 1 } } struct ObservedObjectExampleView: View { // 初始化 @ObservedObject 变量 @ObservedObject private var viewModel = CounterViewModel() var body: some View { VStack { Text("计数: \(viewModel.count)") Button(action: { self.viewModel.increment() }) { Text("增加计数") } } } }在上述代码中,CounterViewModel 是一个符合 ObservableObject 协议的类,包含一个 @Published 属性 count。ObservedObjectExampleView 使用 @ObservedObject 观察 CounterViewModel 的实例。当点击按钮调用 viewModel.increment() 方法时,count 属性的值会改变,SwiftUI 会自动更新 Text 视图以显示新的计数。
3.3 注意事项 对象生命周期:@ObservedObject 不会管理被观察对象的生命周期,因此需要确保对象在视图使用期间不会被销毁。通常在父视图中创建对象并传递给子视图,或者使用 @StateObject 来管理对象的生命周期。 线程安全:@Published 属性的修改应该在主线程上进行,因为 SwiftUI 的视图更新是在主线程上执行的。如果在后台线程中修改 @Published 属性,可能会导致视图更新不一致或崩溃。 四、@EnvironmentObject 4.1 基本概念@EnvironmentObject 用于在整个视图层次结构中共享一个 ObservableObject 实例。与 @ObservedObject 不同的是,@EnvironmentObject 可以在多个视图中轻松访问同一个状态对象,而不需要通过层层传递参数。
4.2 初始化与使用@EnvironmentObject 变量不需要在视图中初始化,它会从视图环境中获取共享的 ObservableObject 实例。在父视图中,需要使用 environmentObject 修饰符将 ObservableObject 实例注入到视图环境中。
import SwiftUI import CombineSwiftUI之状态管理全解析由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“SwiftUI之状态管理全解析”