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

2024-04-14 23:44

本文主要是介绍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 界面调试更加“如虎添翼”。

感谢观赏,再会啦!😎

这篇关于Xcode 15.0 新 #Preview 预览让 SwiftUI 界面调试更加悠然自得的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904358

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

五大特性引领创新! 深度操作系统 deepin 25 Preview预览版发布

《五大特性引领创新!深度操作系统deepin25Preview预览版发布》今日,深度操作系统正式推出deepin25Preview版本,该版本集成了五大核心特性:磐石系统、全新DDE、Tr... 深度操作系统今日发布了 deepin 25 Preview,新版本囊括五大特性:磐石系统、全新 DDE、Tree

Python中的可视化设计与UI界面实现

《Python中的可视化设计与UI界面实现》本文介绍了如何使用Python创建用户界面(UI),包括使用Tkinter、PyQt、Kivy等库进行基本窗口、动态图表和动画效果的实现,通过示例代码,展示... 目录从像素到界面:python带你玩转UI设计示例:使用Tkinter创建一个简单的窗口绘图魔法:用

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

vscode中文乱码问题,注释,终端,调试乱码一劳永逸版

忘记咋回事突然出现了乱码问题,很多方法都试了,注释乱码解决了,终端又乱码,调试窗口也乱码,最后经过本人不懈努力,终于全部解决了,现在分享给大家我的方法。 乱码的原因是各个地方用的编码格式不统一,所以把他们设成统一的utf8. 1.电脑的编码格式 开始-设置-时间和语言-语言和区域 管理语言设置-更改系统区域设置-勾选Bata版:使用utf8-确定-然后按指示重启 2.vscode

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk