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. 持久化与缓存…

进程的地址空间

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

【C++11】线程

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

访问控制系列

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

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;帮助你快速制作高质量的思维导图。 迅捷画图 特点与功…

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…

PiT : 基于池化层Pooling layer的Vision Transformer

CNN的降维原理;随着深度的增加,传统CNN的通道维数增加,空间维数减少。经验表明,这样的空间降维对变压器结构也是有益的,并在原有的ViT模型的基础上提出了一种新的基于池的视觉变压器(PiT)。 1. 引言 ViT与卷积神经网络(CNN)有很大的不同。将输入图像分成1616小块馈送到变压…

LabVIEW软件开发的雷区在哪里?

在LabVIEW软件开发中&#xff0c;有几个需要注意的雷区&#xff0c;以避免常见的错误和提高开发效率&#xff1a; 1. 不良的代码结构 雷区&#xff1a;混乱的代码结构和不清晰的程序逻辑。 后果&#xff1a;导致难以维护和调试的代码&#xff0c;增加了错误和故障的风险。 …

Web3时代的教育技术革新:智能合约在学习管理中的应用

随着区块链技术的发展和普及&#xff0c;Web3时代正在为教育技术带来前所未有的革新和机遇。智能合约作为区块链技术的核心应用之一&#xff0c;不仅在金融和供应链管理等领域展示了其巨大的潜力&#xff0c;也在教育领域中逐渐探索和应用。本文将探讨智能合约在学习管理中的具…

【C++】前缀和:和为K的子数组

1.题目 2.算法 需要借助哈希表&#xff08;查找效率很高&#xff09;。 如果一个区间和为sum&#xff0c;如果它的前缀和为sum-k&#xff0c;那么后缀和一定是K。 3.代码

类与对象(3)

对于类的构造函数我们已经有了初步的了解&#xff0c;这里我们对其拷贝构造函数进行讲解&#xff1a; 目录 拷贝构造函数&#xff1a; 1.拷贝构造函数的作用&#xff1a; 2.系统生成拷贝构造函数的缺陷 3.深拷贝的实现 侧面体现 拷贝构造函数&#xff1a; 这里我们将拷贝…

小程序-模板与配置

一、WXML模板语法 1.数据绑定 2.事件绑定 什么是事件 小程序中常用的事件 事件对象的属性列表 target和currentTarget的区别 bindtap的语法格式 在事件处理函数中为data中的数据赋值 3.事件传参与数据同步 事件传参 &#xff08;以下为错误示例&#xff09; 以上两者的…

Java语言程序设计基础篇_编程练习题**14.29(游戏:豆机)

第十四章第二十九题 **14.29 (游戏&#xff1a;豆机) 请写一个程序&#xff0c;显示编程练习题 7.21 中介绍的豆机&#xff0c;如图 14-52c 所示 代码展示 package chapter_14;import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.layou…

NFS存储、API资源对象StorageClass、Ceph存储-搭建ceph集群和Ceph存储-在k8s里使用ceph(2024-07-16)

一、NFS存储 注意&#xff1a;在做本章节示例时&#xff0c;需要拿单独一台机器来部署NFS&#xff0c;具体步骤略。NFS作为常用的网络文件系统&#xff0c;在多机之间共享文件的场景下用途广泛&#xff0c;毕竟NFS配置方 便&#xff0c;而且稳定可靠。NFS同样也有一些缺点&…