SwiftUI 6.0(Xcode 16)新 PreviewModifier 协议让预览调试如虎添翼

在这里插入图片描述

概览

用 SwiftUI 框架开发过应用的小伙伴们都知道,SwiftUI 中的视图由各种属性和绑定“扑朔迷离”的缠绕在一起,自成体系。

在这里插入图片描述

想要在 Xcode 预览中泰然处之的调试 SwiftUI 视图有时并不是件容易的事。其中,最让人秃头码农们头疼的恐怕就要数如何正确的向预览传入视图内部的状态了。

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

  • 概览
  • 1. PreviewModifier 到底有啥用?
  • 2. 用 PreviewModifier “点缀”预览视图外观
  • 3. PreviewModifier 诞生之前我们如何向预览传送数据?
  • 4. 用 PreviewModifier 注入(inject)预览模拟数据
  • 总结

遵循 SwiftUI 6.0(Xcode 16)新推出的 PreviewModifier 协议,正可谓是:“你好,我好,大家都好”。

不信?且看分晓!Let‘s go!!!😉


1. PreviewModifier 到底有啥用?

从 SwiftUI 6.0 开始,顺便借助 Xcode 16 的东风,苹果推出了全新的 PreviewModifier 协议:

在这里插入图片描述

正如该协议“自夸”的那样:PreviewModifier 可以让 Xcode 预览(Preview)界面和调试数据“浑然天成,融洽无间”。

有了 PreviewModifier,我们即可从两个方面来为预览调试“雪中送炭”:

  • 统一改变预览中视图的外观;
  • 为预览视图传入模拟测试数据;

下面,就让我们依次来看看它们究竟是如何“大施拳脚”的吧。

2. 用 PreviewModifier “点缀”预览视图外观

假若我们希望 Xcode 预览中某些被调试的视图都放在导航容器中,并且根据实际情况增加导航标题和导航栏 Logo。

注意,这些视图的 body 代码自身并没有嵌入到导航视图内,因为这是使用它们的父视图份内的事儿。这意味着,我们必须繁文缛节的在所有预览中将这些视图嵌入到导航视图中去:

#Preview {NavigationStack {ContentView().navigationTitle("SwiftUI 滚动行为演示").toolbar {Text("大熊猫侯佩 @ \(Text("CSDN").foregroundStyle(.red))").foregroundStyle(.orange).font(.headline.weight(.heavy))}}
}

如上代码所示:我们不但要在预览中为每个“潜在的”导航子视图添加导航容器(NavigationStack),还要不厌其烦的为它们设置相应的导航标题和 Logo 视图。

现在,我们看看 PreviewModifier 协议能为我们做些什么吧:

struct NavPreviewHelper: PreviewModifier {var title: Stringfunc body(content: Content, context: Void) -> some View {NavigationStack {content.navigationTitle(title).toolbar {Text("大熊猫侯佩 @ \(Text("CSDN").foregroundStyle(.red))").foregroundStyle(.orange).font(.headline.weight(.heavy))}}}
}

如大家所见,我们创建了一个 NavPreviewHelper 结构,并让其遵循 PreviewModifier 协议。我们只需实现其中的 body 方法,然后将预览测试的视图包裹在导航容器(NavigationStack)内部,并妥善为其设置了标题和预览 Logo。

有了 NavPreviewHelper 这位“贤内助”,我们可以易如反掌的将任何需要“如此炮制”的预览测试视图嵌入到 NavigationStack 中并妥善“装扮”了:

#Preview(traits: .modifier(NavPreviewHelper(title: "SwiftUI 滚动行为演示"))) {ContentView()
}#Preview("另一个视图", traits: .modifier(NavPreviewHelper(title: "另一个视图演示"))) {Text("另一个测试视图!")
}

从下面的演示中大家可以看到,我们的 NavPreviewHelper 就像“预览模版”一样,可供任何有此需求的预览视图使用了:

在这里插入图片描述

我们甚至还能通过 PreviewTrait 扩展,进一步简化 #Preview 宏中 NavPreviewHelper 的调用:

extension PreviewTrait where T == Preview.ViewTraits {@MainActor static func navHelper(_ title: String) -> PreviewTrait<T> {.modifier(NavPreviewHelper(title: title))}
}#Preview(traits: .navHelper("SwiftUI 滚动行为演示")) {ContentView()
}#Preview("另一个视图", traits: .navHelper("另一个视图演示")) {Text("另一个测试视图!")
}

3. PreviewModifier 诞生之前我们如何向预览传送数据?

在 PreviewModifier 降临之前,倘若我们想要为视图传入预览测试数据,在某些场景下非得大费周章一番不可:

#Preview {@Previewable var clock = Clock.newCountClock(name: "大熊猫侯佩的计时器")let container = ModelContainer.previewtry! container.mainContext.save(clock)return CountClockCell(clockID: clock.id).modelContainer(container)
}

如上代码所示:我们需要为所有使用 Clock 托管实例的预览视图“喋喋不休”的初始化测试数据。虽然使用 SwiftUI 6.0 新加入的 @Previewable 宏能够让实现简洁不少,但在每个预览视图之前都来上这么“一坨”代码,恐怕也绝非长久之计。毕竟,它严重违反了 DRYKISS原则。


关于 SwiftUI 6.0(Xcode 16) 中预览新增 @Previewable 宏的使用,请小伙伴们移步如下链接观赏更详细的内容:

  • SwiftUI 6.0(Xcode 16)全新 @Entry 和 @Previewable 宏让开发妙趣横生

4. 用 PreviewModifier 注入(inject)预览模拟数据

现在,我们回到拥有 PreviewModifier 色彩斑斓的“新世界”中吧。

回忆一下之前 NavPreviewHelper 类型的实现:我们实际上完全忽略了 body 方法中的 context 参数(所以将其类型设置为 Void)。其实,这个 context 可以大有作为。

为了让 context 物尽其用,我们需要另外实现一个 makeSharedContext 方法,用它来注入测试模型数据。

现在,我们尝试将前一个需要 Clock 模型数据的预览改写为 PreviewModifier “助人为乐”的形式:

var clockID: UUID?
private struct MockClockData: PreviewModifier {static func makeSharedContext() throws -> ModelContainer {let container = ModelContainer.previewlet clock = Clock.newCountClock(name: "大熊猫的计时器")clockID = clock.idtry container.mainContext.save(clock)return container}func body(content: Content, context: ModelContainer) -> some View {content.modelContainer(context)}
}extension PreviewTrait where T == Preview.ViewTraits {@available(watchOS 11.0, *)@MainActor static var sampleData: Self = .modifier(MockClockData())
}@available(watchOS 11.0, *)
#Preview(traits: .mockClockData) {CountClockCell(clockID: clockID!)
}

从上面的代码可以看到,我们利用 makeSharedContext 方法在指定的 ModelContainer 中生成并保存了所需的测试数据,接下来在 Xcoce 预览中使用这些数据就是水到渠成的事情啦:

在这里插入图片描述

有了这位预览“好帮手”之后,我们现在可以为任何需要 Clock 托管数据的预览视图“套用” MockClockData “测试模版”啦,小伙伴们是不是觉得事倍功半,一步到位了呢?棒棒哒!💯

总结

在本篇博文中,我们介绍了如何使用 SwiftUI 6.0(Xcode 16)中最新的 PreviewModifier 协议让预览调试闲情逸致、如虎添翼。

感谢观赏,再会啦!😎

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

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

相关文章

对redis进行深入学习

目录 1. 什么是redis&#xff1f;1.1 为什么使用redis作为缓存&#xff1f;1.1.0 数据库&#xff08;MySQL&#xff09;与 redis1. 存储介质不同&#xff08;408选手应该都懂hh&#xff09;2. 数据结构优化3. I/O模型差异4. CPU缓存友好性5. 单线程与多线程差异6. 持久化与缓存…

Postcat使用全解析

文章目录 引言官网链接Postcat原理概述基础使用安装与启动创建与发送请求环境变量 高级使用集合与预请求脚本代码生成器 优缺点分析优点缺点 结论 引言 Postcat&#xff0c;作为一款功能丰富的API开发与测试工具&#xff0c;受到了广大开发者的喜爱。它提供了直观的用户界面和…

C语言 二叉树,一个猜动物的小游戏

1. 此项目用到的知识点: 二叉树&#xff0c; struct&#xff0c; 文件读写。 2. 其中最复杂的地方是&#xff1a;复制一个指针的内容&#xff0c;参考&#xff1a;https://stackoverflow.com/questions/39938648/copy-one-pointer-content-to-another 1. 头文件 "node_ut…

进程的地址空间

一、写个代码见一见地址空间 1、问题 在代码中我们在第五秒时会在子进程中改变全局变量 g_val 但是我们发现了一个奇怪的现象&#xff1a;在子进程中改变 g_val &#xff0c;由于进程的独立性&#xff0c;所以子进程和父进程的值不一样是可以理解的&#xff0c;但是为什么变量…

20240718每日后端------------kafka VS RabbitMQ:选择正确的消息代理

目标 消息队列选型 Kafka VS RabbitMQ Kafka Apache Kafka 是一个开源分布式事件流平台&#xff0c;以其高吞吐量、容错性和实时数据处理能力而闻名。 Kafka 遵循发布-订阅模型&#xff0c;生产者将消息写入主题&#xff0c;消费者订阅这些主题以接收消息。 Kafka 将消息存储…

【C++11】线程

本篇文章更多的是熟悉一下C11的线程库接口&#xff0c;与linux的相关线程接口是非常相似的&#xff0c;更多的是将面向过程改为了面向对象。 并没有一些概念的讲解。 想知道线程的相关概念的可以看一看这篇文章及后续 在C11之前&#xff0c;涉及到多线程问题&#xff0c;都是和…

访问控制系列

目录 一、基本概念 1.客体与主体 2.引用监控器与引用验证机制 3.安全策略与安全模型 4.安全内核 5.可信计算基 二、访问矩阵 三、访问控制策略 1.主体属性 2.客体属性 3.授权者组成 4.访问控制粒度 5.主体、客体状态 6.历史记录和上下文环境 7.数据内容 8.决策…

使用TableConvert API将CSV转换为JSON数组

TableConvert API 是一款多功能工具&#xff0c;旨在简化不同数据格式之间的转换过程。通过访问370种不同的转换器&#xff0c;该API可以在包括CSV、Excel、HTML、JSON、Markdown等多种文件类型和结构之间实现无缝数据转换。 为什么选择TableConvert的CSV到JSON数组API&#x…

面试问题:react的Reconciler(调度器)为什么在做异步可中断不用原生Generator,自己做了一个Fiber

首先Generator也是有异步中断功能的但是能他是有传染性的&#xff0c;使用了Generator则需要上下文的其他函数也需要做主改变&#xff0c;这样心智负担比较重&#xff0c;就比如说我定义一个Generator方法&#xff0c;里面有ABC三个函数我分别在B的前面和C的前面放一个yield打断…

Linux: network: device事件注册机制 chatGPT; notify

ChatGPT 在 Linux 内核中,有关网络设备(net-device)的事件注册机制,允许用户在网络设备的状态发生变化(例如设备被删除、添加或修改)时接收通知。这主要通过 netdev 事件通知机制实现。具体来说,内核提供了一组用于注册和处理网络设备事件的 API。 以下是一些关键组件…

memcached 高性能内存对象缓存

memcached 高性能内存对象缓存 memcache是一款开源的高性能分布式内存对象缓存系统&#xff0c;常用于做大型动态web服务器的中间件缓存。 mamcached做web服务的中间缓存示意图 当web服务器接收到请求需要处理动态页面元素时&#xff0c;通常要去数据库调用数据&#xff0c;但…

【快速逆向一/无过程/有源码】《大学》在线投稿系统

逆向日期&#xff1a;2024.07.18 使用工具&#xff1a;Node.js 加密工具&#xff1a;Crypto-js标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 【点赞 收藏 关注 】仅供学习&#xff0c;仅供学习&#xff0c; 本文为快速逆向&#x…

如果制作红星照耀中国思维导图?6个软件帮助你快速制作思维导图

如果制作红星照耀中国思维导图&#xff1f;6个软件帮助你快速制作思维导图 制作《红星照耀中国》思维导图可以帮助更好地理解和梳理书中的重要信息和内容。以下是六款推荐的思维导图软件及其特点和使用方法&#xff0c;帮助你快速制作高质量的思维导图。 迅捷画图 特点与功…

Milvus核心组件(2)---- etcd 详解

目录 背景 etcd 简介 1. 基本概念 2. 数据存储特性 3. KVS的操作 4. 租约(Lease)机制 5. 实际应用场景 Milvus 下的 etcd 服务及存储结构 etcd 服务 端口 存储位置 安全连接信息 嵌入式方式运行 etcd 文件存储结构 解析etcd 文件 连接 etcd server 注意事项…

n2. Web相关知识和工具

Web相关知识和工具 1. http协议相关基础知识2. http协议状态码3. Web相关工具2.1 links2.2 wget2.3 curl2.4 httpie 4. httpd的压力测试工具 1. http协议相关基础知识 URI&#xff1a; Uniform Resource Identifier 统一资源标识&#xff0c;分为URL 和 URN URN&#xff1a;U…

Python基础语法篇(下)+ 数据可视化

Python基础语法&#xff08;下&#xff09; 数据可视化 一、函数&#xff08;一&#xff09;函数的定义&#xff08;二&#xff09;函数的调用和传参 二、文件操作&#xff08;一&#xff09;文件读取和写入&#xff08;二&#xff09;文件对象及方法&#xff08;三&#xff09…

【数学建模】——【线性规划】及其在资源优化中的应用

目录 线性规划问题的两类主要应用&#xff1a; 线性规划的数学模型的三要素&#xff1a; 线性规划的一般步骤&#xff1a; 例1&#xff1a; 人数选择 例2 &#xff1a;任务分配问题 例3: 饮食问题 线性规划模型 线性规划的模型一般可表示为 线性规划的模型标准型&…

达梦数据库的系统视图v$sqltext

达梦数据库的系统视图v$sqltext 在达梦数据库&#xff08;DM Database&#xff09;中&#xff0c;V$SQLTEXT 是一个系统视图&#xff0c;用于显示当前正在执行或最近执行的SQL语句的文本信息。这个视图对于监控和分析数据库中的SQL活动非常有用&#xff0c;尤其是在需要调试性…

【MySQL篇】Percona XtraBackup工具备份指南:常用备份命令详解与实践(第二篇,总共五篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…

银河麒麟搭建ftp服务器

1.先 查看系统架构&#xff0c;我常遇到的一般银河麒麟是arrch64的 lscpu uname -a cat /etc/os-release 去下载对应版本的vsftp.rpm包和ftp包 Index of /NS/ (cs2c.com.cn) 1.安装rpm rpm -ivh *.rpm --nodeps --force #强制安装 2.修改配置文件 vi /etc/vsftpd/vsftpd.co…