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

news2024/12/25 1:34:55

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

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

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

相关文章

Spring第一课,了解IDEA里面的文件,回顾Cookie和Session,获取Session,Cookie,Header的方式

目录 IDEA第一课(熟悉里面内容) 建立连接 -RequestMapping 路由映射 请求 1.传递单个参数​编辑 2.多个参数​编辑 3.传递数组 4.传递一个集合,但是这里我们传递的时候发生了500的错误 简单介绍JSON 回顾Cookie和S…

软文推广中如何提炼好产品卖点,媒介盒子分享

内容同质化的时代下,企业应该如何让用户留下印象,并且成功将产品卖出去,核心思维就在于提炼产品卖点,产品卖点是销量提升的关键,相信企业在推广产品时都会有点困惑,感觉自家产品和竞品比起来只是logo、外观…

【SpringCloud】为什么选择微服务?

一般的平台会遇到的问题: 服务配置复杂。基础服务多,服务的资源配置复杂,传统方式管理服务复杂 服务之间调用复杂。检索服务、用户中心服务等,服务之间的调用复杂,依赖多 服务监控难度大。服务比较多,…

【SpringCloud】什么是微服务?

一、单体架构 单体架构就是把所有业务模块编写在一个项目,最终打包成一个 war 包,进行部署 单体架构的优点: 部署简单:由于是完整的结构体,可以直接部署在一个服务器上即可 技术单一:项目不需要复杂的…

世界这么大,极米投影仪RS Pro 3任意门带你“云旅游”

在繁忙的工作之后,许多小伙伴选择出门旅游,但也有不少人想在家“躺平”。其实,对于当代年轻人来说,行走在钢筋混凝土丛林,在家用智能投影观影娱乐好好放松身心也是不错的选择。有一台投影仪来相伴,能够抚平…

Let’s xrOS 一款让你优先体验社区创作者的 visionOS App工具

Let’s xrOS Apple Vision Pro 发布预示着空间计算时代的到来,让科技爱好者和开发者开始思考如何在新的交互、系统和硬件上打造独特的三维应用。 自 WWDC 2023 的发布会后,社交媒体上涌现了许多精美的 visionOS App 的效果图和演示视频,然而…

Mac安装配置typescript及在VSCode上运行ts

一、Mac上安装typescript sudo npm install -g typescript 测试一下:出现Version则证明安装成功 tsc -v 二、在VSCode上运行 新建一个xxx.ts文件,测试能否运行 console.log("helloworld") 运行报错:ts-node: command not…

【无标题】学习HTML

由于工作需求,学习了一些html的相关知识,最终应用到打印功能上使用。 HTML是指超文本标记语言(HyperText Markup Language)。它是一种用于创建和呈现互联网上页面的标准标记语言。HTML是Web开发的基础,是构建网页和应…

关于SseEmitter(SSE)在本地可以响应,部署到服务器后无法响应的问题

关于SseEmitter(SSE)在本地可以响应,部署到服务器后无法响应的问题 GetMapping(value "/v3/detail", produces MediaType.TEXT_EVENT_STREAM_VALUE) ResponseBody public SseEmitter v3Detail(String id) {SseEmitter emitter new SseEmitter((long) …

探究Kafka原理-2.Kafka基本命令实操

👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码、Kafka原理🔥如果感觉博主的文章还不错的话,请&#x1f44…

【开源】基于JAVA的高校实验室管理系统

项目编号: S 015 ,文末获取源码。 \color{red}{项目编号:S015,文末获取源码。} 项目编号:S015,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

2023年第十六届中国系统架构师大会(SACC2023)-核心PPT资料下载

一、峰会简介 本届大会以“数字转型 架构演进”为主题, 涵盖多个热门领域,如多云多活、海量分布式存储、容器、云成本、AIGC大数据等,同时还关注系统架构在各个行业中的应用,如金融、制造业、互联网、教育等。 与往届相比&#…

StarRocks 算子落盘:让大查询又快又稳

内存是对数据库非常重要的数据存储介质,它承载了所有查询计算的请求,在提升性能、实时分析等场景都有着重要的作用。正是由于内存如此重要,经常会遇到内存不够的情况,从而导致查询被强制终止,甚至对线上其他查询性能产…

UML建模图文详解教程04——对象图

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl本文参考资料:《UML面向对象分析、建模与设计(第2版)》吕云翔,赵天宇 著 对象图 对象图(object diagram)显示了某一时刻的一组…

OSG动画与声音-动画(3)

动画 动画是一种常见的动画形式(Frame ByFrame),其原理是在连续的关键帧中分解动画动作,从另一个方面来说,也就是在时间轴的每帧上逐顿绘制不同的内容,使其连续播放而形成动画。 因为帧动画的帧序列内容不一样,不但给制…

通过 OGNL 注入执行 Confluence 预身份验证远程代码 (CVE-2022-26134)

漏洞描述 Confluence 是由澳大利亚软件公司 Atlassian 开发的基于 Web 的企业 wiki。 02 年 2022 月 <> 日&#xff0c;Atlassian 发布了针对其 Confluence Server 和 Data Center 应用程序的安全公告&#xff0c;强调了一个严重严重的未经身份验证的远程代码执行漏洞。…

java项目之网络在线考试系统(ssm)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的网络在线考试系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; &#xff08;1&#xff09;登录…

python如何快速查找到想要的文档

字多不看版&#xff0c;直接体验 待补充 演示代码 # -*- coding:UTF-8 -*-# region 导入必要的依赖包 import os import subprocess from enum import Enum模块名 pyperclip try:import pyperclip # 需要安装 pyperclip 模块&#xff0c;以支持粘贴板操作 except ImportEr…

Java零基础——SpringMVC篇

1.SpringMVC介绍 SpringMVC是Spring框架中的一个组件&#xff0c;是一个轻量级的web的MVC框架&#xff0c;充当controller,其本质就是一个Servlet。 1.1 传统Servlet的不足 每个请求&#xff0c;都需要定义一个Servlet。虽然可以在service方法中&#xff0c;根据业务标识进行…

「Verilog学习笔记」 输入序列不连续的序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 题目要求检测a的序列&#xff0c;a为单bit输入&#xff0c;每个时刻可能具有不同的值&#xff0c;且并不是每一个数据都是有效的&#xff0c;需要根据data_valid信号进行判…