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

news2025/2/22 19:07:15

在这里插入图片描述

概览

从 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!!!😉


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.coloradmin.cn/o/1591549.html

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

相关文章

计算机服务器中了360后缀勒索病毒怎么办?360后缀勒索病毒解密步骤

网络技术的不断应用与发展,为企业的生产运营提供了极大便利,利用网络可以开展各项工作业务,可以大大提高企业的生产效率,然而,网络是一把双刃剑,在为企业提供便利的同时,也为企业的数据安全带来…

蓝桥杯【第15届省赛】Python B组

这题目难度对比历届是相当炸裂的简单了…… A:穿越时空之门 【问题描述】 随着 2024 年的钟声回荡,传说中的时空之门再次敞开。这扇门是一条神秘的通道,它连接着二进制和四进制两个不同的数码领域,等待着勇者们的探索。 在二进制…

Leetcode刷题之移除元素(C语言版)

Leetcode刷题之移除元素(C语言版) 一、题目描述二、题目解析 一、题目描述 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅…

旧版本jquery升级新版本后如何处理兼容性问题

前言 最近项目在漏洞扫描过程中发现现在的jquery版本受多个跨站点脚本漏洞影响,需要升级jquery版本。 1、首先下载高版本的jquery,我这里升级的是3.6.0 2、对应的bootstrap版本也要升级,这里升级的是3.3.7 本来以为替换完这两个文件后&#…

LeetCode654:最大二叉树

题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点,其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 …

STM32+ESP8266水墨屏天气时钟:文字取模和图片取模教程

项目背景 本次的水墨屏幕项目需要显示一些图片和文字,所以需要对图片和文字进行取模。 取模步骤 1.打开取模软件 2.选择图形模式 3.设置字模选项 注意:本次项目采用的是水墨屏,并且是局部刷新的代码,所以设置字模选项可能有点…

自定义注解(二)——系统日志记录

在上一篇自定义注解(一)——统一请求拦截中对自定义注解做了简单说明及关于统一token认证的应用示例。其实对于自定义注解,还有一种常用的方法是用于系统日志记录,此处的系统日志记录,区别于Slf4j或Log4j把日志文件写入…

Big Data and Cognitive Computing (IF=3.7) 期刊投稿

Special Issue: Artificial Cognitive Systems for Computer Vision 欢迎计算机视觉相关工作的投稿! 影响因子3.7,截止时间2024年12月31日 投稿咨询:lqyan18fudan.edu.cn 投稿网址:https://www.mdpi.com/journal/BDCC/special_iss…

模板方法模式:定义算法骨架的设计策略

在软件开发中,模板方法模式是一种行为型设计模式,它在父类中定义一个操作的算法框架,允许子类在不改变算法结构的情况下重定义算法的某些步骤。这种模式是基于继承的基本原则,通过抽象类达到代码复用的目的。本文将详细介绍模板方…

【算法刷题 | 回溯思想 02】4.12(电话号码的字母组合)

文章目录 4.电话号码的字母组合4.1问题4.2解法:回溯4.2.1回溯思路(1)函数返回值以及参数(2)终止条件(3)遍历过程 4.2.2代码实现 4.电话号码的字母组合 4.1问题 给定一个仅包含数字 2-9 的字符…

阻塞队列和生产消费模型

阻塞队列 阻塞队列的概念 队列相信我们已经不陌生了 之前也学过很多队列 比如: 普通队列 和 优先级队列 两种 这两种队列都是线程不安全的 而我们讲的阻塞队列 刚好可以解决线程安全问题 也是先进先出 并且带有阻塞功能. 阻塞功能是怎么回事呢 就是如果入队的时候阻塞队列为…

AI的智商如何测试?

一、AI的智商测试 AI的智商测试不同于人类的智商测试,因为它涉及到不同类型的智能和功能衡量标准。以下是几种常见的AI智商测试或评估方式: 此图片来源于网络 1. **功能性测试**: - 对于算法或机器学习模型,可以通过标准化的基…

探秘大模型:《提示工程:技巧、方法与行业应用》背后的故事

提示工程是一种新兴的利用人工智能的技术,它通过设计提示引导生成式 AI 模型产生预期的输出,来提升人与 AI 的互动质量,激发 AI 模型的潜力,提升AI的应用水平。 为了让每一个人都拥有驱动大模型的能力,以微软全球副总裁…

maven之pom中的build标签

1、build标签分类 1.1、全局配置&#xff08;project build&#xff09; 针对整个项目的所有情况都有效。 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation"htt…

Linux执行命令监控详细实现原理和使用教程,以及相关工具的使用

Linux执行命令监控详细实现原理和使用教程&#xff0c;以及相关工具的使用。 0x00 背景介绍 Linux上的HIDS需要实时对执行的命令进行监控&#xff0c;分析异常或入侵行为&#xff0c;有助于安全事件的发现和预防。为了获取执行命令&#xff0c;大致有如下方法&#xff1a; 遍…

OJ 古籍翻译 【进制转化】【C】

这里有两个考察点&#xff0c;一个是进制转换&#xff0c;还有一个是以字符串输出 知识点&#xff1a; sprintf(参数一&#xff0c;参数二&#xff0c;参数三) 将参数三按参数二的格式转换后存入参数一中 sprintf与printf用法基本一样&#xff0c;只是sprintf是将值打印到指…

R语言数据可视化:基本绘图系统

目录 plot函数 par函数 hist函数 boxplot函数 plot函数应用实战 全局参数 R语言中有三大绘图系统包括基本绘图系统&#xff0c;Lattice绘图系统&#xff0c;ggplot2绘图系统 基本绘图系统 在R语言中&#xff0c;以下函数通常用于创建和定制图形&#xff1a; plot 函数…

ansible的常见用法

目录 ##编辑hosts文件 ##copy模块##复制过去 ##fetch模块##拉取 ##shell模块 ##好用 ##command模块## ##file模块### ##cron模块### ##crontab 计划任务 ##下载好时间插件 ##script模块 ##yum模块## ##yum下载源配置文件 /etc/yum.repos.d/CentOS-Base.repo ##ser…

时间序列分析 # 平稳性检验和ARMA模型的识别与定阶 #R语言

掌握单位根检验的原理并能解读结果&#xff1b;掌握利用序列的自相关图和偏自相关图识别模型并进行初步定阶。 原始数据在文末&#xff01;&#xff01;&#xff01; 练习1、根据某1971年9月-1993年6月澳大利亚季度常住人口变动&#xff08;单位&#xff1a;千人&#xff09;的…

MySQL 嵌套查询

嵌套查询 是指在一个完整的查询语句之中&#xff0c;包含若干个不同功能的小查询&#xff1b;从而一起完成复杂查询的一种编写形式。包含的查询放在&#xff08;&#xff09;里 &#xff0c; 包含的查询出现的位置&#xff1a; 位置含义SELECT之后把查询结果作为表头使用FROM…