Xcode 15.0 新 #Preview 预览让 SwiftUI 界面调试更加悠然自得

在这里插入图片描述

概览

从 Xcode 15 开始,苹果推出了新的 #Preview 宏预览机制,它无论从语法还是灵活性上都远远超过之前的预览方式。#Preview 不但可以实时预览 SwiftUI 视图,而且对 UIKit 的界面预览也是信手拈来。

在这里插入图片描述

想学习新 #Preview 预览的一些超实用调试小妙招吗?那就“如意如意”随小伙伴们的心意吧!

在本篇博文中,您将学到如下内容:

  • 概览
  • 1. Xcode 15.0 新预览机制简介
  • 2. #Preview 让状态初始化如此轻松!
  • 3. 为什么 #Preview 中不能直接嵌入可变状态?
  • 4 #Preview + @Observable 宏构造可变 @Binding 实参
  • 总结

相信学完本课后,大家对于 Xcode 15+ 预览的使用以及 SwiftUI 界面调试会更加的轻车熟路!

那还等什么呢?让我们马上开始吧!Let‘s preview!!!😉


本文对应的视频课在此,欢迎恣意观赏 😃

Xcode 15.0新 #Preview 预览让调试悠然自得

1. Xcode 15.0 新预览机制简介

从 Xcode 15 开始,苹果借助于 Swift 5.9 宏(Macro)的“东风”,也为我们带来了全新的 #Preview 预览机制。你猜的没错,它其实就是一个宏:

在这里插入图片描述

如上所示:我们将 #Preview 宏定义展开为了其原始代码的实现,大家可以清楚的看到 #Preview 宏背地里到底做了些神马。

在 Xcode 15 之前,小伙伴们需要使用遵循 PreviewProvider 协议的 Previews 结构来帮助我们预览指定的 SwiftUI 视图:

struct LaunchView_Previews: PreviewProvider {static var previews: some View {LaunchView().environmentObject(Model())}
}

而现在,只需一个 #Preview 即可搞定所有,岂不呜呼快哉:

#Preview {LaunchView().environmentObject(Model())
}

为了方便起见,我们还可以非常 nice 的将多个定制的 #Preview 预览内容混合在一起显示:

在这里插入图片描述

如上所示,为了便于观察我们在 #Preview 中指定了不同预览名称以及预览设备的方向和明暗主题等特性,简直小菜一碟。

2. #Preview 让状态初始化如此轻松!

“理想很骨感,现实却很残酷”。

在实际开发中,不可能所有视图都如此简单。在现实的 App 中视图多半都会与模型(数据)相绑定,这意味着我们在预览它们之前需要创建对应的数据,否则预览就不会达到预期效果,显示将是一片“空空如也”。

比如在 SwiftUI 里我们有一个分类选择视图(V2_ChallengeClassSelectView),所有内置(Built in)的分类都是从数据库中读取的,但前提是我们在数据库中已经初始化了这些分类,这是通过调用如下方法来完成的:

V2_ChallengeClassification.initializeData()

所以,我们可能会写出下面的代码以期待 #Preview 预览可以正常工作:

@available(iOS 17.0, *)
#Preview {V2_ChallengeClassSelectView(selecting: .constant(nil)).onAppear {try? V2_ChallengeClassification.initializeData()}
}

不过可惜的是,以上实现无法得偿所愿。原因是我们 V2_ChallengeClassSelectView 视图中的分类数据必须在其 body 显示之前就准备就绪:

@available(iOS 17.0, *)
struct V2_ChallengeClassSelectView: View {@Binding var selecting: V2_ChallengeClassification?let builtInClasses = try? V2_ChallengeClassification.allBuiltInClassifications()
}

对于这种情况,#Preview 宏有一个非常简单的解决方案:我们只需在预览内容之前直接调用初始化代码即可:

@available(iOS 17.0, *)
#Preview {try? V2_ChallengeClassification.initializeData()return V2_ChallengeClassSelectView(selecting: .constant(nil))
}

运行可以看到,我们已经能够在预览中正确显示初始化之后的所有内置分类了:

在这里插入图片描述

3. 为什么 #Preview 中不能直接嵌入可变状态?

大家可能已经发现了,上面示例中的 V2_ChallengeClassSelectView 视图包含一个 selecting 绑定状态:

struct V2_ChallengeClassSelectView: View {   @Binding var selecting: V2_ChallengeClassification?
}

但在我们的预览中,为了“偷懒”实际向其传入的是一个绑定常量:

V2_ChallengeClassSelectView(selecting: .constant(nil))

这样做的后果是:我们无法在预览中改变 selecting 属性的值,也就无法观察到视图中选择所产生的变化了。

小伙伴们可能会觉得,下面的实现可以帮我们摆脱这一问题:

@available(iOS 17.0, *)
#Preview {@State var selecting: V2_ChallengeClassification?try? V2_ChallengeClassification.initializeData()return V2_ChallengeClassSelectView(selecting: $selecting)}

遗憾的是这样做“然并卵”,毫无用处:

在这里插入图片描述

其原因是:与 Xcode 15 之前的旧预览机制类似,嵌入在预览结构中的简单状态实际上是无法被改变的,即使它被 @State 等(可变)限定符所修饰时也是如此。

那么我们如何解决呢?

答案很简单:将可变状态放到 #Preview 外面去!

4 #Preview + @Observable 宏构造可变 @Binding 实参

从 Xcode 15 (Swift 5.9)开始,苹果推出了新的 @Observable 宏帮我们便捷的创建可观察对象。


更多关于 @Observable 宏以及 Observation 框架的详细介绍,小伙伴们可以移步到下面的博文中进一步观赏:

  • Swift 5.9 与 SwiftUI 5.0 中新 Observation 框架应用之深入浅出
  • Swift 5.9 新 @Observable 对象在 SwiftUI 使用中的陷阱与解决

简单来说,我们可以在 #Preview 之外利用 @Observable 宏包裹我们的可变状态,从而可以将其通过绑定传入到对应的视图中去:

@available(iOS 17.0, *)
@Observable
class PreviewModel {var selecting: V2_ChallengeClassification?
}@available(iOS 17.0, *)
#Preview {@State var model = PreviewModel()try? V2_ChallengeClassification.initializeData()return V2_ChallengeClassSelectView(selecting: $model.selecting)
}

注意,在上面的代码示例中我们实际向 V2_ChallengeClassSelectView 视图传递的绑定是 @Observable 可观察对象 model 中的属性。虽然 model 作为 @State 放在了预览内部,不过由于它是一个可观察对象,所以它仍然可以变化自如。

编译运行修改后的代码,我们现在可以在 #Preview 预览界面中顺畅自如的测试 selecting 分类属性改变时的显示逻辑了:

在这里插入图片描述

至此,我们通过上面几个小“栗子”对 Xcode 15 中新的 #Preview 预览机制又有了更深刻的领悟,小伙伴们还不赶快给自己点一个大大的赞吧!👍🏻


想要系统学习 Swift 语言的小伙伴们,千万不要错过我的《Swift 语言开发精讲》专栏哦:

在这里插入图片描述

  • Swift 语言开发精讲

总结

在本篇博文中,我们介绍了 Xcode 15+ 中新的 #Preview 预览机制,并讨论了如何利用 #Preview + @Observable 宏让 SwiftUI 界面调试更加“如虎添翼”。

感谢观赏,再会啦!😎

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

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

相关文章

【GEE实践应用】按照字段提取想要的研究区域

有的时候,我们在GEE中加载研究区域时,我们现有的矢量数据可能不止自己想要的研究区域的范围,这个时候,为了避免在ArcGIS中重新导出打包上传等操作,我们可以在GEE中按照字段进行选择我们想要的研究区域。下面是操作实例…

杰发科技AC7840——CAN通信简介(4)_过滤器设置

0. 简介 注意:过滤器最高三位用不到,因此最高位随意设置不影响过滤器。 1. 代码分析 注意设置过滤器数量 解释的有点看不懂 详细解释...也看不大懂 Mask的第0位是0,其他位都是1(就是F?),那就指定了接收值就是这个数,…

ASP.NET Core 标识(Identity)框架系列(二):使用标识(Identity)框架生成 JWT Token

前言 JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在网络上以 JSON 对象的形式安全地传输信息。 JWT 通常用于在用户和服务器之间传递身份验证信息,以便在用户进行跨域访问时进行身份验证。 JWT 由…

matlab 安装 mingw64(6.3.0),OPENEXR

matlab安装openexr 1. matlab版本与对应的mingw版本选择2. mingw(6.3.0)下载地址:3. matlab2020a配置mingw(6.3.0)流程“4. matlab 安装openexr方法一:更新matlab版本方法二:其他博文方法方法三…

MySQL——链表

主键:非空 唯一(针对整列数据而言) 为了方便管理一般主键都是设置为自增 外键:一张表中的一列的值是另一张表的主键,使用外键建立两张数据表的数据关系 一、两张表连接 将两张表格拼接成一个表 1、格式:s…

爬虫 | 网易新闻热点数据的获取与保存

Hi,大家好,我是半亩花海。本项目是一个简单的网络爬虫,用于从网易新闻的热点新闻列表中提取标题和对应的链接,并将提取到的数据保存到一个 CSV 文件中。 目录 一、技术栈 二、功能说明 三、注意事项 四、代码解析 1. 导入所需…

【C++进阶】RAII思想&智能指针

智能指针 一,为什么要用智能指针(内存泄漏问题)内存泄漏 二,智能指针的原理2.1 RAII思想2.2 C智能指针发展历史 三,更靠谱的shared_ptr3.1 引用计数3.2 循环引用3.3 定制删除器 四,总结 上一节我们在讲抛异…

PostgreSQL入门到实战-第二十九弹

PostgreSQL入门到实战 PostgreSQL中数据分组操作(四)官网地址PostgreSQL概述PostgreSQL中CUBE命令理论PostgreSQL中CUBE命令实战更新计划 PostgreSQL中数据分组操作(四) 如何使用PostgreSQL CUBE生成多个分组集 官网地址 声明: 由于操作系统, 版本更新等原因, 文章所列内容不…

InternlM2

第一次作业 基础作业 进阶作业 1. hugging face下载 2. 部署 首先,从github上git clone仓库 https://github.com/InternLM/InternLM-XComposer.git然后里面的指引安装环境

【Golang学习笔记】从零开始搭建一个Web框架(二)

文章目录 模块化路由前缀树路由 前情提示: 【Golang学习笔记】从零开始搭建一个Web框架(一)-CSDN博客 模块化路由 路由在kilon.go文件中导致路由和引擎交织在一起,如果要实现路由功能的拓展增强,那将会非常麻烦&…

[尚硅谷flink] 检查点笔记

在Flink中,有一套完整的容错机制来保证故障后的恢复,其中最重要的就是检查点。 文章目录 11.1 检查点11.1.1 检查点的保存1)周期性的触发保存2)保存的时间点3)保存的具体流程 11.1.2 从检查点恢复状态11.1.3 检查点算法…

【python】 numpy 中常用随机数函数的使用和记忆(不易混淆)

文章目录 概述固定分布随机数(只需指定形状的随机函数)np.random.randomnp.random.randnp.random.randn 随机范围随机数(需要指定范围和形状的随机函数)np.random.randintnp.random.uniformnp.random.normalnp.random.poisson 代码…

乐写9612手写板实测故障

闲鱼上淘了二手的 ①需要驱动很强的usb口,老usb口会不识别,尤其是笔记本容易不识别,非常容易出现下面这种问题: ②需要microsoft2013以上的,兼容性做的比较差 ③由于可视化,导致数据线容易烧,…

超标量处理器设计:基于竞争的分支预测分支预测的更新

★ 继续学习体系结构的知识。 接着上一讲继续写 ★上一讲:超标量处理器设计:基于全局历史的分支预测-CSDN博客 ★上上一讲:超标量处理器设计:两位饱和计数器&基于局部历史的分支预测-CSDN博客 知识回顾: 基于局部…

策略模式【行为模式C++】

1.概述 策略模式是一种行为设计模式, 它能让你定义一系列算法, 并将每种算法分别放入独立的类中, 以使算法的对象能够相互替换。 策略模式通常应用于需要多种算法进行操作的场景,如排序、搜索、数据压缩等。在这些情况下&#x…

将公式用MathType转换导入LaTex的方法 Mathtype+laTex 混合使用 在mathtype中打latex代码编辑公式

关于LaTex和Word之间孰优孰劣的争论已经持续了很长时间,有些朋友在写论文时还会纠结是用Word好还是用LaTex好,其实他们两也是各有优势,LaTeX 与 Word 是两种不同类型的文本编辑处理系统。Latex是无格式的明文文档,格式保存在源文件…

dbeaver数据库语言编辑器设置jdbc驱动

打开 dbeaver 软件 数据库 -> 驱动管理器 以mysql为例 双击 MySQL -> 库 -> 添加工件 然后 打开maven组件库 官网 找到mysql驱动对应的maven工件地址 复制进去然后确认就行了 参考 大神博客

stm32f103c8t6hal库使用看门狗

STM32F103C8T6是一款性能强大的微控制器,它具有丰富的外设和功能,其中之一就是看门狗(Watchdog)。看门狗是一种重要的硬件设备,它可以在系统出现异常时自动重启系统,以保证系统的稳定运行。我们将详细介绍如…

001vscode为什么设置不了中文?

VSCode中文插件安装 在VSCode中设置中文的首要步骤是安装“Chinese (Simplified) Language Pack for Visual Studio Code”扩展插件。这一过程十分简单,只需打开VSCode,进入扩展市场,搜索“ Chinese (Simplified) Language Pack ”然后点击…

transformer

通过5个条件判定一件事情是否会发生,5个条件对这件事情是否发生的影响力不同,计算每个条件对这件事情发生的影响力多大,写一个transformer模型pytorch程序,最后打印5个条件分别的影响力。 示例一 为了计算每个条件对一件事情发生的影响力&am…