当前位置: 首页 > news >正文

SwiftUI之状态管理全解析

文章目录

    • 引言
    • 一、`@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 属性 countObservedObjectExampleView 使用 @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 Combine

相关文章:

  • tcc编译器教程1 配置tcc编译器环境
  • Python面向对象编程入门:从类与对象到方法与属性
  • Deepseek 模型蒸馏
  • Kotlin语言特性(一):空安全、扩展函数与协程
  • 【华三】SR-MPLS TE 静态配置实验
  • 华为OD-2024年E卷-分批萨[100分]
  • Go 接口使用
  • 计算机毕业设计SpringBoot+Vue.js基于JAVA语言的在线考试与学习交流网页平台(源码+文档+PPT+讲解)
  • 【数据结构】红黑树插入(手算)
  • 2024年时间序列预测领域的SOTA模型总结
  • 【Linux】:网络层(IP 协议 网络通信 全球网络 路由转发)
  • server can‘t find dns01.test.com: SERVFAIL
  • 《Python实战进阶》No 11:微服务架构设计与 Python 实现
  • 算法004——盛最多水的容器
  • 【前端基础】Day 6 CSS定位
  • 数据库原理与使用全解析:从理论到实践
  • React低代码项目:问卷编辑器 I
  • 什么是Agentic AI?(Doubao-1.5-pro-32k 大模型开启联网回答)
  • Qt | 实战继承自QObject的IOThread子类实现TCP客户端(安全销毁)
  • 迅雷下载实现原理解析
  • 备案名称和网站名称不一致/湖南seo推广
  • 云服务器和网站备案吗/互联网营销推广渠道
  • 门户网站开发的背景和意义/seo公司品牌哪家好
  • 高端建站属于外包公司么/河南纯手工seo
  • 雕刻业务网站怎么做/百度推广一天烧多少钱
  • wordpress 上传网站/seo月薪