【SwiftUI】7.预览及其内部机制

news/2024/7/20 23:04:56 标签: swiftui, ios, swift

上一篇讲到了组件及组件化,从概念和优/缺点两个方向说明了组件化的意义,更为重要的是,组件和组件化是一个在编程领域,放之四海皆可以的概念,理解和运用它是非常必要的,希望大家能掌握。今天我们介绍另一个特性--预览(Preview).

概念

预览是苹果给SwiftUI新添加的一个重要特性,也可以算得上是一个重大突破。它可以直接在macOS上进行渲染并显示界面(即所见即所得),很类似Flutter的Hot Reloading。熟悉Hot Reloading技术的同学都知道,它给我们编程带来很多的方便。

然而,相比Hot Reloading技术,预览又有些不同,甚至可以说更好一些。因为Hot Reloading技术需要运行App,并且当调整界面或数据状态发生变化的时,需要重启App。而预览就完全不需要做这些事情(不用运行App;数据变化也不需要重启App)。

再说明一点,预览的实现机制整体概括为:Xcode工具对代码进行静态分析(依赖于SwiftSyntax框架),然后找到所有遵循ProviewProvider协议的类型,进而对此进行渲染和显示。

讲完了概念,用示例图来展示预览情况。

现象

上图表示:

1.左边是编写代码区域,右边是实时预览区域,实现了所见即所得的效果。

2.红框标注了遵循ProviewProvider协议。

介绍完了预览的概念和样式。大家一定很好奇预览功能是怎么实现的?它的内部机制是怎么样的呢?下面我们一起看下。

内部机制

我们先拿个工程来举例。先创建一个SwiftUI的新工程(注意:先不要写任何代码,也不启动预览功能)。如下图所示

然后找到DerivedData目录。找一个后缀.preview-thunk.swift的文件

此时,在这个目录上是找不到的(因为没有编译,连工程目录都没有)。

接着编译(Command+B)工程(记得开启预览功能).就可以在DerivedData目录上找到 .preview-thunk.swift文件了。对于本机来说,.preview-thunk.swift的完整路径为:

DerivedData/工程目录/Build/Intermediates.noindex/Previews/TestSwiftUIDemo5/Intermediates.noindex/TestSwiftUIDemo5.build/Debug-iphonesimulator/TestSwiftUIDemo5.build/Objects-normal/x86_64/ContentView.5.preview-thunk.swift.

文件效果如下图所示

然后打开该文件。会显示如下代码

@_private(sourceFile: "ContentView.swift") import TestSwiftUIDemo5
import SwiftUI
import SwiftUI

extension ContentView_Previews {
    @_dynamicReplacement(for: previews) private static var __preview__previews: some View {
        #sourceLocation(file: "/Users/hyh/Documents/MyProject/TestSwiftUIDemo5/TestSwiftUIDemo5/ContentView.swift", line: 19)
        __designTimeSelection(ContentView(), "#5016.[2].[0].property.[0].[0]")
    #sourceLocation()
    }
}

extension ContentView {
    @_dynamicReplacement(for: body) private var __preview__body: some View {
        #sourceLocation(file: "/Users/hyh/Documents/MyProject/TestSwiftUIDemo5/TestSwiftUIDemo5/ContentView.swift", line: 12)
        __designTimeSelection(Text(__designTimeString("#5016.[1].[0].property.[0].[0].arg[0].value", fallback: "Hello, world!"))
            .padding(), "#5016.[1].[0].property.[0].[0]")
    #sourceLocation()
    }
}

import struct TestSwiftUIDemo5.ContentView
import struct TestSwiftUIDemo5.ContentView_Previews

这个代码不用看懂,我们只需要了解下面几个特性:

  • @_private(sourceFile: ): 让当前代码可以访问原本外部无法访问的变量和函数,这样我们就无需在项目代码中提高访问权限。简单来说,通过该函数能直接访问一些不能访问的变量或函数。

  • #sourceLocation(file: ,line: ):负责将衍生代码中发生的崩溃等调试信息反映在我们写的代码上,帮助开发者找到对应的源代码位置。等同于错误日志输入。

  • @_dynamicReplacement(for: ):指定某个方法作为另一个方法的动态替代方法。在上面的代码中,主要是__preview__previews 函数并让它作为预览入口。

  • 最后两行import代码,是导入struct TestSwiftUIDemo5.ContentView和

    struct TestSwiftUIDemo5.ContentView_Previews 两个结构体的相关信息(包含变量),保证代码的编译成功。

以上代码,简单来说,就是确定一个入口函数,并且依赖上自己编写的代码的相关信息。

这里注意下

在该目录下有两个.preview-thunk.swift文件,经过实践验证:这两个文件内容基本一样,一起变化(代码一变化,两文件内容一起变化),所以存在两个一样的文件。

然而,Xcode如何加载预览视图的呢?

这个就需要查看ContentView.5.preview-thunk.dylib(.dylib后缀是动态库)。如下图所示

然后打开.dylib文件,需要在在当前目录下,在终端执行

nm ./ContentView.5.preview-thunk.dylib | grep ' T '
 //该命令作用是罗列出.dylib文件中的符号

执行结果如下图

其实,该动态库只有一个_main 方法。在该方法中,主要进行了定义预览相关的环境设置、设置预览初始状态等操作。然后,再创建了用于预览的进程。并通过 XPC 在预览进程与 Xcode 之间进行通信,最后实现了在 Xcode 中预览特定视图的目的。这就是Xcode加载预览视图的整个过程。

最后总结下预览的工作流程。

预览的工作流程(该流程描述来自网络)

  • Xcode 生成预览衍生代码文件

  • Xcode 编译整个项目,解析文件、获取预览视图实现、准备依赖的其他资源

  • Xcode 编译预览衍生代码文件,创建动态库

  • Xcode 启动预览线程,在其中加载 _XCPreviewKit 框架和预览衍生文件生成的 dylib

  • XCPreviewKit 框架在预览线程中创建预览窗口

  • Xcode 通过 XPC 发送消息指令, _XCPreviewKit 框架更新预览窗口,并在两个线程建进行交互与同步

  • 用户在 Xcode 界面中看到预览效果

以上就是预览的概念和内部机制的介绍。

参考

https://zhuanlan.zhihu.com/p/631420119

https://www.guardsquare.com/blog/behind-swiftui>swiftui-previews


http://www.niftyadmin.cn/n/5206971.html

相关文章

数据报文去哪儿了

背景 今天遇到一个诡异的现象,当接口附加一个IP时,主IP业务正常,附加IP死活不行,tcpdump抓包确可以正常抓到到业务的报文,但是在PREROUTING raw添加规则确没有命中,说明报文没有到netfilter框架内&#xff…

竞赛选题 题目:垃圾邮件(短信)分类 算法实现 机器学习 深度学习 开题

文章目录 1 前言2 垃圾短信/邮件 分类算法 原理2.1 常用的分类器 - 贝叶斯分类器 3 数据集介绍4 数据预处理5 特征提取6 训练分类器7 综合测试结果8 其他模型方法9 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于机器学习的垃圾邮件分类 该项目…

砖家测评:腾讯云标准型S5服务器和s6性能差异和租用价格

腾讯云服务器CVM标准型S5和S6有什么区别?都是标准型云服务器,标准型S5是次新一代云服务器规格,标准型S6是最新一代的云服务器,S6实例的CPU处理器主频性能要高于S5实例,同CPU内存配置下的标准型S6实例要比S5实例性能更好…

【Python基础】多线程编程

🌈欢迎来到Python专栏 🙋🏾‍♀️作者介绍:前PLA队员 目前是一名普通本科大三的软件工程专业学生 🌏IP坐标:湖北武汉 🍉 目前技术栈:C/C、Linux系统编程、计算机网络、数据结构、Mys…

易涝积水点监测,内涝积水监测仪安装

城市内涝对人们来讲会有很多影响,比如出行需要绕远路或者家中涌入污水导致淤泥堆积,这还有可能让屋内的家具受到破坏,既影响正常生活也造成了经济损失。在街道上还可能对交通、通讯、电力等基础设施造成严重威胁。因此政府如果能实时监测路面…

老师检查家庭作业的作用

在教育体系中,老师检查家庭作业是一种常见的教学方式,旨在帮助学生巩固课堂所学知识,提高自学能力,以及培养良好的学习习惯。家庭作业是学生学习过程中不可或缺的一环,而老师对家庭作业的检查则起到了至关重要的作用。…

创建文件夹的shell脚本

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> 很简单,先判断文件夹是否存在,不存在则创建。具体如下: #!/bin/bash # 判断文件夹是否存在 if [ ! -d "$folder…

万宾科技智能井盖传感器使用方式,具有什么效果?

有问题的井盖可能导致人们在行走或驾驶时不经意地踩中或碰到,从而导致摔倒、扭伤或交通事故等安全事故。有问题的井盖可能会破坏井盖和下方污水管道之间的密封性,导致污水泄漏。这不仅会对环境造成污染,还可能对公共卫生和健康构成威胁。 将智…