ios(swiftui) 属性包装器详解
目录
1. @State
2. @Binding
3. @ObservedObject 和@Published
4. @StateObject
5. @EnvironmentObject和@Environment
6. @AppStorage
在 SwiftUI 中,属性包装器用于增强和管理视图的状态,以及处理视图与数据模型之间的绑定和交互。下面是一些常见的属性包装器:
1. @State
使用@State属性包装器的变量是私有的,并且仅在创建它们的视图中使用。当用户与界面交互引起状态改变时,SwiftUI会重新绘制依赖这些状态的视图。这是响应式编程思想在SwiftUI中的表现。
这里有一个简单的例子,演示如何使用@State:
import SwiftUIstruct ContentView: View {// 使用@State修饰的计数器变量@State private var counter = 0var body: some View {VStack {Text("你点击了 \(counter) 次")Button("点击我") {// 因为counter是@State变量,改变它的值将会重新绘制视图self.counter += 1}}}
}
在这个例子中,每当counter变量的值改变时(例如,用户每次点击按钮时),SwiftUI都会重新调用body属性,因此文本显示的计数器值会更新。
2. @Binding
允许视图共享并能够双向绑定到外部的状态。这常用于将父视图的状态传递给子视图。
@Binding 是一个属性包装器,它允许子视图共享父视图的状态。@Binding 为子视图提供对父视图的某个状态的引用,这样一来,子视图可以读取这个状态并能够在发生更改时更新它,而不是维护它自己的状态副本。
当你使用 @Binding 时,它实际上是对一个 @State、@ObservedObject、@EnvironmentObject 或其他具有可观察状态的源的引用。
以下是一个简单的例子说明如何使用 @Binding:
首先,假设你有一个父视图,使用 @State 管理一个布尔值 isOn:
struct ParentView: View {@State private var isOn = falsevar body: some View {VStack {Toggle("Switch", isOn: $isOn)ChildView(isOn: $isOn) // 传递 @State 给子视图}}
}
接着,你有一个子视图 ChildView,需要使用从父视图传递的 isOn 状态:
struct ChildView: View {@Binding var isOn: Bool // 使用 @Binding 接收父视图的状态var body: some View {Text(isOn ? "It's on" : "It's off")}
}
在这个例子中,子视图 ChildView 可以直接显示 isOn 的状态,也能够在不同的视图层级之间共享和修改这个状态,如果 isOn 在子视图中被修改,父视图中的 @State 也会相应更新。
3. @ObservedObject 和@Published
@Published 通常用于 ObservableObject 里的属性。当给标记为 @Published 的属性赋值时,这个改动会发布出去,所有观察者都可以接收到这个改变。
@ObservedObject和 @Binding 类似,但是用于当数据模型遵守 ObservableObject 协议时。它会使得视图自动更新以响应可观察对象中发生的变化。
声明一个外部来源的可观察对象。当这个可观察对象发生变化时,使用 @ObservedObject 标记的视图会被重新绘制。这使得在SwiftUI中实现数据的双向绑定和状态管理变得更加简单和直观。
这里有一些基础的概念和使用示例:
可观察对象 (Observable Object)
可观察对象通常是遵循了 ObservableObject 协议的类,并且通过 @Published 属性包装器来声明那些当变化时需要通知视图重新渲染的属性。
import Combine
import SwiftUIclass ExampleModel: ObservableObject {@Published var score = 0
}
使用 @ObservedObject
在SwiftUI视图中使用 @ObservedObject 来观察这些对象的变化:
struct ExampleView: View {@ObservedObject var model: ExampleModelvar body: some View {Text("Score: \(model.score)").onTapGesture {model.score += 10}}
}
在这个例子中,每次点击文本时,模型的 score 属性会增加10。由于 score被标记为 @Published,且 ExampleModel 遵循了 ObservableObject,所以每次 score 改变时,使用了 @ObservedObject 的 ExampleView 都将重新绘制,反映出新的分数。
注意事项
- 当使用
@ObservedObject时,你需要确保这个对象在视图更新时不会被销毁或者重新创建,否则会丢失其状态。这通常意味着这个对象是由外部传递给视图的,或者在视图的父级或共享环境(如使用EnvironmentObject)中保存。 - 对于视图自己的内部状态,你通常会使用
@State或者@StateObject作为属性包装器。
@StateObject vs @ObservedObject
不要混淆 @ObservedObject 和 @StateObject:
@StateObject用于视图对数据所有权的声明(它负责创建这个对象),并且它会在视图重新绘制时保持对象的生命周期。它在SwiftUI 2.0中引入,用来取代在视图体内部初始化@ObservedObject的用法。@ObservedObject通常是从父视图或其他部分的应用程序传递过来的,并且视图不负责管理其生命周期。
在实践中,你需要根据实际的数据所有权和生命周期管理要求来选择使用 @StateObject 还是 @ObservedObject。
4. @StateObject
- 在 SwiftUI 2.0 中引入,用来初始化可观察对象,并且拥有对该对象的所有权。也就是说它会构建并保持对象直到视图的整个生命周期结束。
@StateObject 与 @ObservedObject 类似,都用于引用遵守 ObservableObject 协议的类实例。这种遵守 ObservableObject 协议的类会发布对其属性的更改,这样 SwiftUI 就可以在这些属性变化时更新 UI。
两者之间的区别在于它们的用途和生命周期:
-
@StateObject应当用于创建和拥有对应的 observable object,即表示该视图负责初始化这个对象,并且是这个对象的“源头”或首个拥有者。这保证了状态对象不会因为视图的重新渲染而被重新创建。 -
@ObservedObject应当用于那些已经由其他部分创建的 observable objects。其实际上是对从外部传入的状态对象的引用,意味着它不负责该对象的生命周期。
在以下情形下使用 @StateObject:
import SwiftUIclass ExampleModel: ObservableObject {@Published var count: Int = 0// Other properties and methods
}struct ExampleView: View {@StateObject var model = ExampleModel()var body: some View {// UI elements that use 'model'Text("Count: \(model.count)").onTapGesture {model.count += 1}}
}
这个例子展示了如何在视图中创建一个 @StateObject 以存储和管理状态。在视图的生命周期中,ExampleModel 对象将保持活动并不会因为视图的重建而被销毁或重置。使用这种方式,你可以确保状态的一致性并避免不必要的对象重建
5. @EnvironmentObject和@Environment
@EnvironmentObject可以从环境中获取共享的数据模型,这个属性包装器不负责创建对象,而是假定共享的对象已经被其它某部分的代码添加到环境中去了
@Environment 允许视图访问从 iOS 提供的环境值,例如 @Environment(\.presentationMode) 可以访问视图的表现模式。
@EnvironmentObject 和 @Environment 都是用于数据传递和状态共享的属性包装器,不过它们在使用中有一些区别。
(1)@EnvironmentObject:
@EnvironmentObject 用于向视图的层次结构中传递共享的数据对象。你可以在应用的任意位置注入这个共享的数据对象,让其他需要这些数据的视图可以直接访问它,而不需要通过视图参数来逐层传递。这增加了数据共享的便捷性,尤其是在大型项目中。它通常用于类似于全局状态或者应用中的共享数据模型。
使用@EnvironmentObject时,首先需要在某个视图之外的地方创建一个可观察对象。该对象需要遵守ObservableObject协议。然后,在视图层次结构的上游 somewhere(比如在顶级视图或者场景代理中) 你需要将这个对象作为环境对象注入。在需要访问这些数据的视图中,你使用@EnvironmentObject来声明这个依赖,然后 Swift UI会自动为你提供这个对象。
示例代码:
class SharedData: ObservableObject {@Published var value: String = "Hello, World!"
}struct ContentView: View {// 注入环境对象@EnvironmentObject var sharedData: SharedDatavar body: some View {Text(sharedData.value)}
}let sharedData = SharedData()
let contentView = ContentView().environmentObject(sharedData)
如果尝试访问未注入的@EnvironmentObject,应用会崩溃。
(2)@Environment:
@Environment用于读取从环境中传递下来的值,如系统设置、接口样式、布局方向等。相比@EnvironmentObject,@Environment更多用于访问由 SwiftUI 框架维护的预设值,而不是自定义的可观测对象。一个常见的使用场景是,读取系统的颜色方案(.colorScheme),或者是当前的时间区域(.timeZone)。
示例代码:
struct ContentView: View {// 从环境中读取值@Environment(\.colorScheme) var colorSchemevar body: some View {Text("The current color scheme is \(colorScheme == .dark ? "Dark" : "Light")")}
}
在这个例子中,我们没有注入任何自定义对象到环境中。相反,我们直接访问了 SwiftUI 环境中的预设值。
两者虽然看起来类似,但根据使用场景的不同,开发者可以选择最适合的一个。@EnvironmentObject 更适合那些全局共享状态的情景,而@Environment更适合需要访问由系统维护的环境值。
6. @AppStorage
-在 SwiftUI 2.0 中引入,用于简单的数据持久化,当读写 UserDefaults 时自动同步视图。
@AppStorage 是一个 Swift 属性包装器(property wrapper),提供了一种将用户默认设置或应用设置存储在 UserDefaults 中的便捷方式。使用 @AppStorage, 你可以创建一个绑定到 UserDefaults 中具体键的属性,当该属性的值发生变化时,UserDefaults 会自动更新,反之亦然。
在 SwiftUI 中,@AppStorage 的使用十分普遍,特别是用来响应某些设置或偏好的变化,并据此更新UI。这种数据持久化的方式适用于存储少量的用户配置信息,例如:标记应用是否为首次启动、用户的暗黑模式偏好、或者任何小型配置数据。
这里是一个基本的使用示例:
import SwiftUIstruct ContentView: View {// 使用 @AppStorage 监视对应的 UserDefaults 键值对,当值变化时自动更新视图。@AppStorage("isDarkMode") private var isDarkMode = falsevar body: some View {VStack {Text(isDarkMode ? "Dark Mode is ON" : "Dark Mode is OFF")// 切换按钮可以更改 @AppStorage 绑定的值Button("Toggle Dark Mode") {isDarkMode.toggle()}}}
}
在上面的例子中,isDarkMode 属性绑定到了 UserDefaults 中的 "isDarkMode"键。当你点击按钮切换 isDarkMode 的值时,这个值会自动保存到 UserDefaults并在下次应用启动时保留。同时 UI 也会响应这个值的变化并立即更新。这种简单的数据绑定方法让你能够不必直接操作 UserDefaults API 而轻松保存和访问用户设置。
官网:SwiftUI | Apple Developer Documentation
相关文章:
ios(swiftui) 属性包装器详解
目录 1. State 2. Binding 3. ObservedObject 和Published 4. StateObject 5. EnvironmentObject和Environment 6. AppStorage 在 SwiftUI 中,属性包装器用于增强和管理视图的状态,以及处理视图与数据模型之间的绑定和交互。下面是一些常见…...
【智能家居】面向对象编程OOP和设计模式(工厂模式)
面向对象编程 类和对象 面向对象编程和面向过程编程区别 设计模式 软件设计模式按类型分 工厂模式 面向对象编程 面向对象编程(Object-Oriented Programming,OOP)是一种程序设计范式,其中程序被组织成对象的集合,每…...
Docker安装Memcached+Python调用
简介:Memcached是一个通用的分布式内存缓存系统。它通常用于通过在RAM中缓存数据和对象来加速动态数据库驱动的网站,以减少必须读取外部数据源(如数据库或API)的次数。Memcached的API提供了一个分布在多台机器上的非常大的哈希表。…...
网页开发 HTML
目录 HTML概述 HTML结构 HTML标签语法 基本标签 标题标签 换行标签 段落标签 文本格式化标签 特殊符号 div和span标签 超链接标签 锚点 img标签 列表标签 表格标签 表单标签 HTML概述 HTML,即超文本标记语言(HyperText Markup Language …...
SHAP(五):使用 XGBoost 进行人口普查收入分类
SHAP(五):使用 XGBoost 进行人口普查收入分类 本笔记本演示了如何使用 XGBoost 预测个人年收入超过 5 万美元的概率。 它使用标准 UCI 成人收入数据集。 要下载此笔记本的副本,请访问 github。 XGBoost 等梯度增强机方法对于具有…...
LeetCode 8 字符串转整数
题目描述 字符串转换整数 (atoi) 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 读入字符串并丢弃无用的前导空格检查下一…...
前缀和 LeetCode1423. 可获得的最大点数
几张卡牌 排成一行,每张卡牌都有一个对应的点数。点数由整数数组 cardPoints 给出。 每次行动,你可以从行的开头或者末尾拿一张卡牌,最终你必须正好拿 k 张卡牌。 你的点数就是你拿到手中的所有卡牌的点数之和。 给你一个整数数组 cardPoi…...
探索意义的深度:自然语言处理中的语义相似性
一、说明 语义相似度,反应出计算机对相同内容,不同表达的识别能力。因而识别范围至少是个句子,最大范围就是文章,其研究方法有所区别。本文将按照目前高手的研究成绩,作为谈资介绍给诸位。 二、语义相似度简介 自然语言…...
WT2605-24SS高品质录音语音芯片:实时输出、不保存本地,引领音频技术新潮流
随着科技的快速发展,高品质音频技术成为了现代社会不可或缺的一部分。在这个追求高品质、高效率的时代,唯创知音推出的WT2605-24SS高品质录音芯片,以其独特的功能和卓越的性能,引领着音频技术的新潮流。 首先,WT2605-…...
Git 合并冲突解决步骤
Git 合并冲突解决步骤 1. 找到并打开冲突文件 定位到发生冲突的文件。可以通过 Git 的命令行输出找到这些文件。例如: pom.xmlsrc/main/java/com/zzm/config/SecurityConfig.javasrc/main/java/com/zzm/service/chat/UserConversationsServiceImpl.javasrc/main/…...
Windows核心编程 注册表
目录 注册表概述 打开关闭注册表 创建删除子健 查询写入删除键值 子健和键值的枚举 常用注册表操作 注册表概述 注册表是Windows操作系统、硬件设备以及客户应用程序得以正常运行和保存设置的核心"数据库",也可以说是一个非常巨大的树状分层结构的…...
【算法专题】二分查找
二分查找 二分查找1. 二分查找2. 在排序数组中查找元素的第一和最后一个位置3. 搜索插入位置4. x 的平方根5. 山脉数组的峰顶索引6. 寻找峰值7. 寻找旋转排序数组中的最小值8. 点名 二分查找 1. 二分查找 题目链接 -> Leetcode -704.二分查找 Leetcode -704.二分查找 题…...
中国消费电子行业发展趋势及消费者需求洞察|徐礼昭
一、引言 近年来,随着科技的飞速发展,消费电子行业面临着前所未有的挑战与机遇。本文将从行业发展趋势、消费者需求洞察以及企业数字化转型的方向和动作三个方面,对消费电子行业进行深入剖析。 二、消费电子行业发展趋势 5G技术的普及和应…...
UE学习C++(1)创建actor
创建新C类 在 虚幻编辑器 中,点击 文件(File) 下拉菜单,然后选择 新建C类...(New C Class...) 命令: 此时将显示 选择父类(Choose Parent Class) 菜单。可以选择要扩展的…...
【CTA认证】Android8实现android6以下的应用运行时也要申请权限
需求 CTA入网认证,要求低版本比如Android6以下的应用,运行时,也需要有运行时权限(Runtime Permission)功能,不能默认就取到权限,必须人工在设置中打开才可。 环境 Android 8 实现 frameworks 修改思路是所有APP都…...
gRPC Java、Go、PHP使用例子
文章目录 1、Protocol Buffers定义接口1.1、编写接口服务1.2、Protobuf基础数据类型 2、服务器端实现2.1、生成gRPC服务类2.2、Java服务器端实现 3、java、go、php客户端实现3.1、Java客户端实现3.2、Go客户端实现3.3、PHP客户端实现 本文例子是在Window平台测试,Ja…...
前端知识笔记(十九)———px,em,rem,vw,vh之间的区别
一,px(像素):像素是屏幕上显示的最小单位,它是固定的,不随页面缩放而改变大小。在响应式设计中,使用像素单位可能会导致布局在不同屏幕尺寸上显示不一致。例如:现在在你电脑上一个字…...
docker部署frp穿透内网
文章目录 (1)部署frps服务器(2)部署frpc客户端(3)重启与访问frp(4)配置nginx反向代理 (1)部署frps服务器 docker安装参考文档:docker基本知识 1…...
使用pytorch从零开始实现迷你GPT
生成式建模知识回顾: [1] 生成式建模概述 [2] Transformer I,Transformer II [3] 变分自编码器 [4] 生成对抗网络,高级生成对抗网络 I,高级生成对抗网络 II [5] 自回归模型 [6] 归一化流模型 [7] 基于能量的模型 [8] 扩散模型 I, 扩散模型 II…...
tp6框架 万级数据入库 php函数优化
将万级数据入库并判断有无 没有则新增 上篇是用mysql的replace into实现 本篇是另一种方法 这是我的数据格式: $data [ [ KCH > value1, other_column1 > value_other1_1, other_column2 > value_other2_1, ], [ KCH > value2, other_column…...
利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命
在华东塑料包装行业面临限塑令深度调整的背景下,江苏艾立泰以一场跨国资源接力的创新实践,重新定义了绿色供应链的边界。 跨国回收网络:废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点,将海外废弃包装箱通过标准…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
