Swift 5.9 与 SwiftUI 5.0 中新 Observation 框架应用之深入浅出
0. 概览
Swift 5.9 一声炮响为我们带来全新的宏(Macro)机制,也同时带来了干霄凌云的 Observation 框架。
Observation 框架可以增强通用场景下的使用,也可以搭配 SwiftUI 5.0 而获得双剑合璧的更强威力。
在本篇博文,您将学到如下内容:
- 0. 概览
- 1. @Observable 宏
- 2. 通用情境下如何观察 Observable 对象?
- 3. Observable 对象与 SwiftUI 珠联璧合
- 4. 被“抛弃的” @EnvironmentObject
- 5. 在视图中将不可变 Observable 对象转换为可变对象的妙招
- 6. 总结
那么,就让我们赶快进入 Observation 奇妙的世界吧!
Let‘s go!!!😉
1. @Observable 宏
简单来说,Observation 框架为我们提供了集鲁棒性(robust)、安全性、高性能等三大特性为一身的 Swift 全新观察者设计模式。
它的核心功能在于:监视对象状态,并在改变时做出反应!
在 Swift 5.9 中,我们可以非常轻松的通过 @Observable 宏将普通类“转化为”可观察(Observable)类。自然,它们的实例都是可观察的:
@Observable
final class Hero {var name: Stringvar power: Intinit(name: String, power: Int) {self.name = nameself.power = power}
}@Observable
final class Model {var title: Stringvar createAt: Date?var heros: [Hero]init(title: String, heros: [Hero]) {self.title = titleself.createAt = Date.nowself.heros = heros}
}
如上代码所示,我们定义了两个可观察类 Model 和 Hero,就是这么简单!
2. 通用情境下如何观察 Observable 对象?
在一个对象成为可观察之后,我们可以通过 withObservationTracking() 方法随时监听它状态的改变:
我们可以将对象需要监听的属性放在 withObservationTracking() 的 apply 闭包中,当且仅当( Hero 中其它属性的改变不予理会)这些属性发生改变时其 onChange 闭包将会被调用:
let hero = Hero(name: "大熊猫侯佩", power: 5)func watching() {withObservationTracking({NSLog("力量参考值:\(hero.power)")}, onChange: {NSLog("改变之前的力量!:\(hero.power)")watching()})
}watching()hero.name = "地球熊猫"
hero.power = 11
hero.power = 121
以上代码输出如下:
使用 withObservationTracking() 方法有 3 点需要注意:
- 它默认只会被调用 1 次,所以上面为了能够重复监听,我们在 onChange 闭包里对 watching() 方法再次进行了调用;
- withObservationTracking() 方法的 apply 闭包不管如何都会被调用 1 次,即使其监听的属性从未改变过;
- 在监听闭包中只能得到属性改变前的旧值;
目前,上面测试代码在 Xcode 15 的 Playground 中编译会报错,提示如下:
error: test15.playground:8:13: error: external macro implementation type ‘ObservationMacros.ObservableMacro’ could not be found for macro ‘Observable()’
final class Hero {
^Observation.Observable:2:180: note: ‘Observable()’ declared here
@attached(member, names: named(_$observationRegistrar), named(access), named(withMutation)) @attached(memberAttribute) @attached(extension, conformances: Observable) public macro Observable() = #externalMacro(module: “ObservationMacros”, type: “ObservableMacro”)
小伙伴们可以把它们放在 Xcode 的 Command Line Tool 项目中进行测试:
3. Observable 对象与 SwiftUI 珠联璧合
要想发挥 Observable 对象的最大威力,我们需要 SwiftUI 来一拍即合。
在 SwiftUI 中,我们无需再显式调用 withObservationTracking() 方法来监听改变,如虎添翼的 SwiftUI 已为我们自动完成了所有这一切!
struct ContentView: View {let model = Model(title: "地球超级英雄", heros: [])var body: some View { NavigationStack {Form {LabeledContent(content: {Text(model.title)}, label: {Text("藏匿点名称")})LabeledContent(content: {Text(model.createAt?.formatted(date: .omitted, time: .standard) ?? "无")}, label: {Text("更新时间")})Button("刷新") {// SwiftUI 会自动监听可观察对象的改变,并刷新界面model.title = "爱丽丝仙境兔子洞"model.createAt = Date.now}}.navigationTitle(model.title)}}
}
注意,上面代码中 model 属性只是一个普通的 let 常量,即便如此 model 的改变仍会反映到界面上:
4. 被“抛弃的” @EnvironmentObject
有了 Swift 5.9 中新 Observation 框架加入游戏,在 SwiftUI 5.0 中 EnvironmentObject 再无用武之地,我们仅用 Environment 即可搞定一切!
早在 SwiftUI 1.0 版本时,其就已经提供了 Environment 对应的构造器:
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
@frozen @propertyWrapper public struct Environment<Value> : DynamicProperty {...}
有了新 Observation 框架的入驻,结合其 Observable 可观察对象,Environment 可以再次大放异彩:
struct HeroListView: View {@Environment(Model.self) var modelvar body: some View {List(model.heros) { hero inHStack {Text(hero.name).font(.headline)Spacer()Text("\(hero.power)").font(.subheadline).foregroundStyle(.gray)}}}
}struct ContentView: View {@State var model = Model(title: "地球超级英雄", heros: [.init(name: "大熊猫侯佩", power: 5),.init(name: "孙悟空", power: 1000),.init(name: "哪吒", power: 511)])var body: some View { NavigationStack {Form {NavigationLink(destination: HeroListView().environment(model)) {Text("查看所有英雄")}}.navigationTitle(model.title)}}
}
现在,即使跨越多重层级关系我们也可以只通过 @Environment 而不用 @EnvironmentObject 来完成状态的间接传递了,是不是很赞呢?👍🏻
5. 在视图中将不可变 Observable 对象转换为可变对象的妙招
介绍了以上这许多,就还剩一个主题没有涉及:**Observable 对象的可变性!
**
为了能够在子视图中更改对应的可观察对象,我们可以用 @Bindable 修饰传入的 Observable 对象:
struct HeroView: View {@Bindable var hero: Herovar body: some View {Form {TextField("名称", text: $hero.name)TextField("力量", text: .init(get: {String(hero.power) }, set: {hero.power = Int($0) ?? 0}))}}
}
不过,对于之前 @Environment 那个例子来说,如何达到子视图能够修改传入的 @Environment 可观察对象呢?
别急,我们可以利用称为“临时可变(Temporary Variable)”的技术将原先不可变的可观察对象改为可变:
extension Hero: Identifiable {var id: String {name}
}struct HeroListView: View {@Environment(Model.self) var modelvar body: some View {// 在 body 内将 model 改为可变@Bindable var model = modelVStack {List(model.heros) { hero inHStack {Text(hero.name).font(.headline)Spacer()Text("\(hero.power)").font(.subheadline).foregroundStyle(.gray)}}.safeAreaInset(edge: .bottom) {// 绑定可变 model 中的状态以修改英雄名称TextField("", text: $model.heros[0].name).padding()} }}
}
运行效果如下:
“临时可变”这一技术可以用于视图中任何化“不变”为“可变”的场景中,当然对于直接视图间对象的传递,我们可以使用 @Bindable 这一更为“正统”的方法。
6. 总结
在本篇博文中,我们讨论了在 Swift 5.0 和 SwiftUI 5.0 中大放异彩 Observation 框架的使用,并就诸多技术细节问题给与了详细的介绍,愿君喜欢。
感谢观赏,再会!😎
相关文章:
Swift 5.9 与 SwiftUI 5.0 中新 Observation 框架应用之深入浅出
0. 概览 Swift 5.9 一声炮响为我们带来全新的宏(Macro)机制,也同时带来了干霄凌云的 Observation 框架。 Observation 框架可以增强通用场景下的使用,也可以搭配 SwiftUI 5.0 而获得双剑合璧的更强威力。 在本篇博文,…...
【已解决】在 Vite 项目中使用 eslint-config-ali 时遇到的解析错误
错误还原 搭建 Vite 项目 pnpm create vite my-vue-app --template vue-ts安装 eslint-config-ali pnpm i -D eslint-config-ali typescript-eslint/parser typescript-eslint/eslint-plugin eslint-plugin-import eslint-import-resolver-typescript vue-eslint-parser esl…...
蓝桥杯每日一题2023.10.5
3420. 括号序列 - AcWing题库 题目描述 题目分析 对于这一我们需要有前缀知识完全背包 完全背包的朴素写法: #include<bits/stdc.h> using namespace std; const int N 1010; int n, m, v[N], w[N], f[N][N]; int main() {cin >> n >> m;fo…...
PyTorch实例:简单线性回归的训练和反向传播解析
文章目录 🥦引言🥦什么是反向传播?🥦反向传播的实现(代码)🥦反向传播在深度学习中的应用🥦链式求导法则🥦总结 🥦引言 在神经网络中,反向传播算法…...
Arcgis提取玉米种植地分布,并以此为掩膜提取遥感影像
Arcgis提取玉米种植地分布上,并以此为掩膜提取遥感影像 一、问题描述 因为之前反演是整个研究区,然而土地利用类型有很多类,只在农田或者植被上进行反演,需要去除水体、建筑等其他类型,如何处理得到下图中只有耕地类…...
软件工程与计算总结(四)项目管理基础
目录 一.项目和项目管理 二.团队组织与管理 三.软件质量保障 四.软件配置管理 五.项目实践 一.项目和项目管理 1.软件开发远不是纯粹的编程,随着软件规模的增长,软件开发活动也变得越来越复杂~ 2.软件项目就是要将所有的软件开发活动组织起来&#…...
【Python】datetime 库
# timedelta(days, seconds, microseconds,milliseconds, minutes, hours, weeks) 默认按顺序传递参数 # 主要介绍 datetime.datetime 类 # 引入 from datetime import datetime today datetime.now() # 获取当前时间 2023-10-05 15:58:03.218651 today1 datetime.utcnow() #…...
从0开始python学习-28.selenium 需要图片验证的登录
url https://test.com/login driver.get(url) # 获取登录页面需要输入账号密码进行模拟登录操作 user driver.find_element(By.XPATH,//*[id"login"]/div[2]/div/form[2]/div[2]/div/div/input).send_keys(username) pwd driver.find_element(By.XPATH,//*[id&qu…...
Nginx搭建Rtmp流媒体服务,并使用Ffmpeg推流
文章目录 1.rtmp流媒体服务框架图2.nginx配置3.配置nginx4.使用ffmpeg推流5.实时推摄像头流 本项目在开发板上使用nginx搭建流媒体服务,利用ffmpeg进行推流,在pc上使用vlc media进行拉流播放。 1.rtmp流媒体服务框架图 2.nginx配置 下载:wge…...
IDEA 将一个普通Java工程转化为maven工程
打开IntelliJ IDEA并打开Java工程。 在项目窗口中,右键单击项目名称,选择“Add Framework Support”。 在弹出的窗口中,选择“Maven”。 在“Maven Information”窗口中,填写Group Id、Artifact Id和Version等基本信息。 点击…...
linux下的永久保存行号
linux下的永久保存行号 1.首先 这里是引用 输入命令:vi ~/.vimrc 其次 这里是引用 输入命令 set number...
92岁高龄的创始人张忠谋谈台积电发展史
一、张忠谋和台积电 在台北一间办公室里,张忠谋最近拿出一本印有彩色图案的旧书。它的标题是《VLSI 系统导论》,这是一本研究生水平的教科书,描述了计算机芯片设计的复杂性。92岁的张先生满怀敬意地举起它。 92岁高龄的台积电创始人张忠谋 “…...
【VIM】VIm初步使用
玩转Vim-从放弃到入门_哔哩哔哩_bilibili...
教育类《中学政史地》收稿方向-投稿邮箱
教育类《中学政史地》收稿方向-投稿邮箱 《中学政史地》收稿方向:中学政治、历史、地理类稿件 《中学政史地》创办于1987年,是我国唯一一份集中学政治、历史、地理三门学科为一体的综合性月刊。每月两期,分初中版和高中版。以服务学生、服务…...
数据库的备份与恢复
数据备份的重要性 备份的主要目的是灾难恢复。 在生产环境中,数据的安全性至关重要。 任何数据的丢失都可能产生严重的后果。 造成数据丢失的原因: 程序错误人为操作错误运算错误磁盘故障灾难(如火灾、地震)和盗窃 数据库备份…...
string类的模拟实现(万字讲解超详细)
目录 前言 1.命名空间的使用 2.string的成员变量 3.构造函数 4.析构函数 5.拷贝构造 5.1 swap交换函数的实现 6.赋值运算符重载 7.迭代器部分 8.数据容量控制 8.1 size和capacity 8.2 empty 9.数据修改部分 9.1 push_back 9.2 append添加字符串 9.3 运算符重载…...
C 函数指针
就像指针可以指向一般变量、数组、结构体那样,指针也可以指向函数。 函数指针的主要用途是向其他函数传递“回调”,或者模拟类和对象。 形式如下: int (*POINTER_NAME)(int a, int b) 这类似于指向数组的指针可以表示所指向的数组。指向函数…...
zkVM设计性能分析
1. 引言 本文主要参考: 2023年9月ZKSummit10 Wei Dai 1k(x) & Terry Chung 1k(x)分享视频 ZK10: Analysis of zkVM Designs - Wei Dai & Terry Chung 当前有各种zkVM,其设计思想各有不同,且各有取舍,本文重点对现有各z…...
调用gethostbyname实现域名解析(附源码)
VC常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...&a…...
面向无线传感器网络WSN的增强型MODLEACH设计与仿真(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
前端页面初步开发
<template><div><el-card class"box-card" style"height: 620px"><el-input v-model"query.name" style"width:200px" placeholder"请输入用户姓名"></el-input>   …...
【赠书活动第3期】《构建新型网络形态下的网络空间安全体系》——用“价值”的视角来看安全
目录 一、内容简介二、读者受众三、图书目录四、编辑推荐五、获奖名单 一、内容简介 经过30多年的发展,安全已经深入到信息化的方方面面,形成了一个庞大的产业和复杂的理论、技术和产品体系。 因此,需要站在网络空间的高度看待安全与网络的…...
基于SpringBoot的智能推荐的卫生健康系统
目录 前言 一、技术栈 二、系统功能介绍 用户管理 科室类型管理 医生信息管理 健康论坛管理 我的发布 我的收藏 在线咨询 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 前言 随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在…...
几种开源协议的区别(Apache、MIT、BSD、MPL、GPL、LGPL)
作为一名软件开发人员,你一定也是经常接触到开源软件,但你真的就了解这些开源软件使用的开源许可协议吗? 你不会真的认为,开源就是完全免费吧?那么让我们通过本文来寻找答案。 一、开源许可协议简述 开源许可协议是指开…...
通过usb串口发送接收数据
USB通信使用系统api,USB转串口通信使用第三方库usb-serial-for-android, 串口通信使用Google官方库android-serialport-api。x 引入包后在本地下载的位置:C:\Users\Administrator\.gradle\caches\modules-2\files-2.1 在 Android 中&#x…...
Python3数据科学包系列(三):数据分析实战
Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 Python3数据科学包系列(三):数据分析实战 国庆中秋宅家自省: Pyth…...
UE4.27.2 自定义 PrimitiveComponent 出现的问题
目录 CreatePrimitiveUniformBufferImmediateFLocalVertexFactory 默认构造函数GetTypeHashENQUEUE_RENDER_COMMANDnull resource entry in uniform buffer parameters FLocalVertexFactory 在看大象无形,其中关于静态物体网络绘制的代码出错的 bug 我也搞了一会………...
【docker】数据卷和数据卷容器
一、如何管理docker容器中的数据? 二、数据卷 1、数据卷原理 将容器内部的配置文件目录,挂载到宿主机指定目录下 数据卷默认会一直存在,即使容器被删除 宿主机和容器是两个不同的名称空间,如果想进行连接需要用ssh,…...
HTML——列表,表格,表单内容的讲解
文章目录 一、列表1.1无序(unorder)列表1.2 有序(order)列表1.3 定义列表 二、表格**2.1 基本的表格标签2.2 演示 三、表单3.1 form元素3.2 input元素3.2.1 单选按钮 3.3 selcet元素 基础部分点击: web基础 一、列表 …...
Mongodb学习
一、初步了解 1.1 Mongodb 是什么 MongoDB 是一个基于分布式文件存储的数据库,官方地址 https://www.mongodb.com/ 1.2 数据库是什么 数据库(DataBase)是按照数据结构来组织、存储和管理数据的 应用程序 1.3 数据库的作用 数据库的主要…...
wordpress优化加速/百度一下首页网页
一、在服务平台创建App 二、下载sdk,添加库文件 三、添加所需权限 <uses-permission android:nam…...
网店网站怎么做的/百度爱采购怎么推广
HDU 5733 题意:给出四面体的四个顶点,求出其内切球的球心坐标和半径,如果不存在内切球,输出"O O O O"。 tags:一堆公式。。可以做模板了 我们可以将平面上的四点得到由同一个点出发的三个矢量。这样就可以计…...
兰州医院网站制作/2021百度新算法优化
(一)、了解文档/视结构 MFC应用程序模型历经多年以有了相当大的发展。有一个时期,它只是个使用应用程序对象和主窗口对象的简单模型。在这个模型中,应用程序的数据作为成员变量保持在框架窗口类中,在框架窗口的客户区…...
淮北专业三合一网站开发/如何用html制作一个网页
大家在面试时肯定遇见过面试题为:问题:try{}里有一个return语句,那么紧跟在这个try后的finally{}里的代码会不会被执行,什么时候被执行,在return前还是后?如果没有实际编码过,八九不离十都不会有…...
wordpress设置注册观看/手机优化大师
这个错误是制作热力图的时候遇到的。这个原因是热力图传入的数据是一个2维的数据,你传入的是一个 1维的数据。 你只需要将传入的数据reshape即可。可以先使用arry转换格式,reshape(-1,1)即可使用...
wordpress 文章统计/网站推广软件免费观看
下面几个网址有一些 Linux命令的在线手册,而且还是中文的,还可以搜索。非常方便 Linux命令手册 Linux命令大全 Linux中文man在线手册 每日一linux命令转载于:https://www.cnblogs.com/javaee6/p/4736482.html...