【SwiftUI】7.預覽及其內部機制

上一篇講到了組件及組件化,從概念和優/缺點兩個方向說明了組件化的意義,更為重要的是,組件和組件化是一個在編程領域,放之四海皆可以的概念,理解和運用它是非常必要的,希望大家能掌握。今天我們介紹另一個特性--預覽(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 SwiftUIextension 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.pswp.cn/news/163776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/163776.shtml
英文地址,請注明出處:http://en.pswp.cn/news/163776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Element UI的Tabs 標簽頁位置導航欄去除線條

在實際開發中,我們調整了相關樣式,導致導航欄的相關樣式跟隨不上,如下圖所示: 因為我跳轉了前邊文字的樣式并以在導航欄添加了相關頭像,導致右邊的線條定位出現問題,我在想,要不我繼續調整右邊…

開發B2B商城的意義

開發B2B商城的意義主要體現在以下幾個方面: 采購成本低:利用互聯網采購,B2B商城的采購商可直接通過線上完成全部流程操作,在提高采購效率的同時,大大降低了B2B工業品企業采購成本。推廣優勢大:B2B商城的曝…

YM5411 WIFI 5模塊 完美替代AP6256

YM5411是沃特沃德推出的一款低成本,低功耗的模塊,該模塊具有Wi-Fi(2.4GHz和5GHz IEEE 802.11 a/b/g/n/ac)藍牙(BT5.0)功能,并通過了SRRC認證,帶mesh,完美替換AP6256。高度…

OpenHarmony之NAPI框架介紹

張志成 誠邁科技高級技術專家 NAPI是什么 NAPI的概念源自Nodejs,為了實現javascript腳本與C庫之間的相互調用,Nodejs對V8引擎的api做了一層封裝,稱為NAPI。可以在Nodejs官網(https://nodejs.org/dist/latest-v20.x/docs/api/n-api…

【python爬蟲】scrapy在pycharm 調試

scrapy在pycharm 調試 1、使用scrapy創建一個項目 scrapy startproject tutorial 2、在朋友pycharm中調試scrapy 2.1 通過文件run.py調試 在根目錄下新建一個文件run.py(與scrapy.cfg文件的同一目錄下), debug ‘run’即可 # -*- coding:utf-8 -*- from scrapy import c…

深入淺出理解libevent——2萬字總結

概述 libevent,libev,libuv都是c實現的異步事件庫,注冊異步事件,檢測異步事件,根據事件的觸發先后順序,調用相對應回調函數處理事件。處理的事件包括:網絡 io 事件、定時事件以及信號事件。這三個事件驅動著服務器的運…

數字人是真人嗎?

引言: 隨著科技的不斷進步,數字人作為一種新興技術正逐漸嶄露頭角。數字人是通過計算機生成的虛擬人物,具備逼真的外貌和行為,令人難以分辨其與真人的差異。本文將探討數字人是否可以被視為真人,并探索數字人技術在各個…

柯橋生活日語學習,打工人的日語你會嗎?

打工人在日語里有幾種說法: アルバイト 這是最常用的稱呼,直接對應中文的“打工”。 例句: 學生の頃はスーパーでアルバイトをしていた。(我學生時代在超市打過工。) バイト これはアルバイトの略稱でよく使われる。(這是アルバイト的簡稱,也很常用。) 例句: バイト先が決…

《第一行代碼:Android》第三版-2.4.1 if 語句

本文主要講解if語句,kotlin的if語句是可以有返回值的,就是if語句的最后一句話就是返回值。 /*** You can edit, run, and share this code.* play.kotlinlang.org*/fun main() {println("Hello, world!!!") val largelargerNumber(5,9) prin…

如何提高希音、亞馬遜、國際站店鋪流量轉化,自養號優勢及測評底層環境邏輯

隨著全球貿易數字化程度加快,尤其是跨境電商的發展日新月異,在外貿出口占比越來越高,在這其中,亞馬遜作為全球實力強勁的在線零售平臺之一,吸引了大量的優秀賣家。 而這也加劇了亞馬遜平臺的競爭程度,尤其…

HCIP數據通信——BGP協議

引言 我之前寫過一篇介紹ISIS的文章,我打算把BGP知識總結以后再做實驗。那么現在就講述一下BGP的一些特點和概念。 BGP特點 BGP屬于EGP(EGP也是BGP前身,指的是具體協議,被淘汰了成為了BGP),無類協議。 它…

C++(14):解決lambda生命期問題

C++(11):局部函數lambda_c++11 函數中定義函數-CSDN博客 中通過實例列舉了lambda使用過程中可能會有變量生命期問題。 C++14中可以通過重新定義變量,并轉移,解決這個問題: #include <iostream> using namespace std;class A { public:A(int data):m_data(data){cou…

繼承中:一般函數的virtual虛函數特性、析構函數的virtual虛函數特性

1、一般的同名函數 c規定&#xff0c;當一個成員函數被聲明為虛函數后&#xff0c;其派生類中的同名函數都自動成為虛函數。因此&#xff0c;在子類重新聲明該虛函數時&#xff0c;可以加&#xff0c;也可以不加&#xff0c;但習慣上每一層聲明函數時都加virtual,使程序更加清…

postgresql數據庫中update使用的坑

簡介 在數據庫中進行增刪改查比較常見&#xff0c;經常會用到update的使用。但是在近期發現update在oracle和postgresql使用卻有一些隱形區別&#xff0c;oracle 在執行update語句的時候set 后面必須跟著1對1的數據關聯而postgresql數據庫卻可以一對多&#xff0c;這就導致數據…

完整的工程項目管理流程是怎么樣的?

閱讀本文你將了解工程項目管理的完整流程&#xff1a;一、項目啟動階段&#xff1b;二、項目規劃階段&#xff1b;三、項目執行階段&#xff1b;四、項目收尾階段&#xff1b;五、項目總結與反饋。 這是一個工程項目管理的完整流程&#xff1a; 項目啟動階段&#xff1a;也就…

xlsxwriter.exceptions.FileCreateError: [Errno 13] Permission denied: ‘E:

xlsxwriter.exceptions.FileCreateError: [Errno 13] Permission denied: ‘E:\、、、、、’ 如果你嘗試了各種修改文件權限的方法都還不行的話 有可能是因為你打開了想要修改的文件&#xff0c;關閉就好啦

Android12 ROM定制導讀

一、前言 本專欄出現的原因: 沉淀自己,距離上一篇博客已經過去幾個月了,筆者最近工作上的事情非常忙,導致博文斷更了,今天忙里偷閑有一段短暫的時間,把這段時間遇到的問題準備整理一下,以文章的形式記錄下來。Android10的專欄也會慢慢更新。讓筆者最為感慨的就是Androi…

C語言分支限界法求解01背包問題

分支限界法是一種求解優化問題的算法&#xff0c;針對01背包問題&#xff0c;它可以通過在搜索過程中剪枝&#xff0c;減少搜索空間的大小&#xff0c;提高算法的效率。 具體來說&#xff0c;分支限界法會將當前狀態下的可行解集合分成若干個子集&#xff0c;每個子集代表一條…

Java特殊文件讀取案例Properties

代碼 package com.itheima.d1;import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.util.Properties;public class Test3 {public static void main(String[] args) throws Exception {//目標&#xff1a;讀取屬性文件…

SpringBoot通過@Scheduled實現定時任務

Spring自帶的定時任務系統&#xff0c;使用注解時必須指定任意一個參數&#xff08;屬性&#xff09;&#xff1a;cron、fixedDelay或fixedRate&#xff1b; 1. 啟動類添加開啟注解 EnableScheduling 2. cron參數 /** * cron 一共可以有7個參數 以空格分開 其中年不是必須參…