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 SwiftUIstruct StateExampleView: View {// 初始化 @State 变量并设置默认值@State private var isFavorite = falsevar 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: Stringvar 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 = 0func 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/71159.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis 高可用性:如何让你的缓存一直在线,稳定运行?

🎯 引言:Redis的高可用性为啥这么重要? 在现代高可用系统中,Redis 是一款不可或缺的分布式缓存与数据库系统。无论是提升访问速度,还是实现数据的高效持久化,Redis 都能轻松搞定。可是,当你把 …

面试题:说一下你对DDD的了解?

面试题:说一下你对DDD的了解? 在面试中,关于 DDD(领域驱动设计,Domain-Driven Design) 的问题是一个常见的技术考察点。DDD 是一种软件设计方法论,旨在通过深入理解业务领域来构建复杂的软件系统。以下是一个清晰、详细的回答模板,帮助你在面试中脱颖而出: DDD 的定义…

Redis---缓存穿透,雪崩,击穿

文章目录 缓存穿透什么是缓存穿透?缓存穿透情况的处理流程是怎样的?缓存穿透的解决办法缓存无效 key布隆过滤器 缓存雪崩什么是缓存雪崩?缓存雪崩的解决办法 缓存击穿什么是缓存击穿?缓存击穿的解决办法 区别对比 在如今的开发中&…

Android Logcat 高效调试指南

工具概览 Logcat 是 Android SDK 提供的命令行日志工具&#xff0c;支持灵活过滤、格式定制和实时监控&#xff0c;官方文档详见 Android Developer。 基础用法 命令格式 [adb] logcat [<option>] ... [<filter-spec>] ... 执行方式 直接调用&#xff08;通过ADB守…

【定昌Linux系统】部署了java程序,设置开启启动

将代码上传到相应的目录&#xff0c;并且配置了一个.sh的启动脚本文件 文件内容&#xff1a; #!/bin/bash# 指定JAR文件的路径&#xff08;如果JAR文件在当前目录&#xff0c;可以直接使用文件名&#xff09; JAR_FILE"/usr/local/java/xs_luruan_client/lib/xs_luruan_…

Java 8 中,可以使用 Stream API 和 Comparator 对 List 按照元素对象的时间字段进行倒序排序

文章目录 引言I 示例对象II List 按时间字段倒序排序: 使用 `Stream` 和 `Comparator` 排序方法 1:使用 `Comparator.comparing`方法 2:使用 `Comparator.reversed`方法 3:自定义 `Comparator`输出结果III 注意事项**时间字段类型**:**空值处理**:IV 总结引言 案例:在线用…

jvm内存模型,类加载机制,GC算法,垃圾回收器,jvm线上调优等常见的面试题及答案

JVM内存模型 JVM内存模型包括哪些区域 答案&#xff1a;JVM内存模型主要包括以下区域&#xff1a; 程序计数器&#xff1a;是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的字节码的行号指示器&#xff0c;用于记录正在执行的虚拟机字节码指令的地址。Java虚拟机…

git clone的时候出现出现error

报错如下&#xff1a; Collecting githttps://github.com/haotian-liu/LLaVA.git Cloning https://github.com/haotian-liu/LLaVA.git to /tmp/pip-req-build-360q6tt1 Running command git clone --filterblob:none --quiet https://github.com/haotian-liu/LLaVA.git /t…

Minio搭建并在SpringBoot中使用完成用户头像的上传

Minio使用搭建并上传用户头像到服务器操作,学习笔记 Minio介绍 minio官网 MinIO是一个开源的分布式对象存储服务器&#xff0c;支持S3协议并且可以在多节点上实现数据的高可用和容错。它采用Go语言开发&#xff0c;拥有轻量级、高性能、易部署等特点&#xff0c;并且可以自由…

vue3中ref和reactive响应式数据、ref模板引用(组合式和选项式区别)、组件ref的使用

目录 Ⅰ.ref 1.基本用法&#xff1a;ref响应式数据 2.ref模板引用 3.ref在v-for中的模板引用 ​4.ref在组件上使用 ​5.TS中ref数据标注类型 Ⅱ.reactive 1.基本用法&#xff1a;reactive响应式数据 2.TS中reactive标注类型 Ⅲ.ref和reactive的使用场景和区别 Ⅳ.小结…

javascript实现雪花飘落效果

本文实现雪花飘落效果的 JavaScript 网页设计案例&#xff0c;代码实现如下&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

项目准备(flask+pyhon+MachineLearning)- 3

目录 1.商品信息 2. 商品销售预测 2.1 机器学习 2.2 预测功能 3. 模型评估 1.商品信息 app.route(/products) def products():"""商品分析页面"""data load_data()# 计算当前期间和上期间current_period data[data[成交时间] > data[成…

FPGA开发,使用Deepseek V3还是R1(3):系统级与RTL级

以下都是Deepseek生成的答案 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;1&#xff09;&#xff1a;应用场景 FPGA开发&#xff0c;使用Deepseek V3还是R1&#xff08;2&#xff09;&#xff1a;V3和R1的区别 FPGA开发&#xff0c;使用Deepseek V3还是R1&#x…

实现 Leaflet 多类型点位标记与聚合功能的实战经验分享

在现代的地理信息系统&#xff08;GIS&#xff09;应用中&#xff0c;地图功能是不可或缺的一部分。无论是展示商业网点、旅游景点还是公共服务设施&#xff0c;地图都能以直观的方式呈现数据。然而&#xff0c;当数据量较大时&#xff0c;地图上可能会出现大量的标记点&#x…

企微审批中MySQL字段TEXT类型被截断的排查与修复实践

在MySQL中&#xff0c;TEXT类型字段常用于存储较大的文本数据&#xff0c;但在一些应用场景中&#xff0c;当文本内容较大时&#xff0c;TEXT类型字段可能无法满足需求&#xff0c;导致数据截断或插入失败。为了避免这种问题&#xff0c;了解不同文本类型&#xff08;如TEXT、M…

【常见BUG】Spring Boot 和 Springfox(Swagger)版本兼容问题

???欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老…

HTTP 协议的发展历程:从 HTTP/1.0 到 HTTP/2.0

HTTP 协议的发展历程&#xff1a;从 HTTP/1.0 到 HTTP/2.0 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是 Web 的基础协议&#xff0c;用于客户端和服务器之间的通信。从 HTTP/1.0 到 HTTP/2.0&#xff0c;HTTP 协议经历了多次重大改…

apload-lab打靶场

1.提示显示所以关闭js 上传<?php phpinfo(); ?>的png形式 抓包&#xff0c;将png改为php 然后放包上传成功 2.提示说检查数据类型 抓包 将数据类型改成 image/jpeg 上传成功 3.提示 可以用phtml&#xff0c;php5&#xff0c;php3 4.先上传.htaccess文件&#xff0…

金融支付行业技术侧重点

1. 合规问题 第三方支付系统的平稳运营&#xff0c;严格遵循《非银行支付机构监督管理条例》的各项条款是基础与前提&#xff0c;其中第十八条的规定堪称重中之重&#xff0c;是支付机构必须牢牢把握的关键准则。 第十八条明确指出&#xff0c;非银行支付机构需构建起必要且独…

Cherry Studio + 火山引擎 构建个人AI智能知识库

&#x1f349;在信息化时代&#xff0c;个人知识库的构建对于提高工作效率、知识管理和信息提取尤为重要。尤其是当这些知识库能结合人工智能来智能化地整理、分类和管理数据时&#xff0c;效果更为显著。我最近尝试通过 Cherry Studio 和 火山引擎 来搭建个人智能知识库&#…