前言
前段時(shí)間筆者組內(nèi)同事十分快速地開(kāi)發(fā)了一個(gè)應(yīng)用(不妨設(shè)應(yīng)用名為QiShareDemo)归敬,筆者在使用8+128的Mac Air 運(yùn)行項(xiàng)目的時(shí)候琉闪,發(fā)現(xiàn)項(xiàng)目編譯時(shí)間比較久和橙,查看了相關(guān)資料,并做了部分實(shí)踐芋酌,落地了這篇文章增显。
筆者在 clone 了 QiShareDemo 后,發(fā)現(xiàn)全量編譯編譯項(xiàng)目的編譯時(shí)間為105.207s脐帝;
后來(lái)經(jīng)過(guò)筆者的部分優(yōu)化編譯時(shí)間處理后同云,全量編譯項(xiàng)目的時(shí)間縮短為44.573s;
當(dāng)然這里還可以繼續(xù)做優(yōu)化堵腹,可以根據(jù)項(xiàng)目中具體的代碼的編譯耗時(shí)排序炸站,處理那些編譯耗時(shí)較長(zhǎng)的代碼。
一疚顷、名詞簡(jiǎn)介
下邊筆者對(duì)本文中提到的名詞做一個(gè)簡(jiǎn)單介紹旱易。
1. 全量編譯
以Xcode編譯過(guò)程為例,筆者理解的全量編譯的一種情況為:把Xcode 編譯項(xiàng)目時(shí)生成的Derived Data 刪除后腿堤,再次編譯項(xiàng)目的過(guò)程阀坏。
2. 增量編譯
以Xcode編譯過(guò)程為例,筆者理解的增量編譯的一種情況為:Xcode 已編譯過(guò)項(xiàng)目的情況下笆檀,我們又修改了部分文件忌堂,那么編譯的時(shí)候,就會(huì)編譯我們修改過(guò)的文件酗洒,及引用過(guò)相關(guān)文件的文件士修。
3. Swift Compiler
如果項(xiàng)目不是 Objective-C 和 Swift 混編的項(xiàng)目而是純 Swift 項(xiàng)目,那么編譯過(guò)程用的是 Swift Compiler樱衷,筆者在下文中第三部分的2.1.2部分有提到詳情棋嘲。關(guān)于編譯的更多詳情可以查看 淺談編譯過(guò)程
二、Swift 項(xiàng)目的編譯過(guò)程
使用 Xcode 查看項(xiàng)目具體編譯過(guò)程的方式如下:
1. 用 Xcode 查看項(xiàng)目具體編譯過(guò)程
用 Xcode 查看項(xiàng)目編譯過(guò)程方式:command + b 編譯項(xiàng)目矩桂,在 Xcode 中沸移,按下圖方式查看具體編譯過(guò)程。
筆者根據(jù) Xcode 編譯項(xiàng)目過(guò)程,做了如下 Swift 項(xiàng)目編譯過(guò)程示意圖阔籽。
2. 查看項(xiàng)目編譯時(shí)間
我們的目的是要優(yōu)化項(xiàng)目的編譯時(shí)間流妻,那么首先我們應(yīng)該知道當(dāng)前編譯時(shí)間。
查看項(xiàng)目編譯時(shí)間的方式為:在終端中輸入如下命令:defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
之后在 Xcode 頂部的 切換Scheme和運(yùn)行設(shè)備的那一欄中即可看到具體編譯時(shí)間笆制。
查看具體編譯時(shí)間方式如下圖所示:
上圖是查看項(xiàng)目總體編譯時(shí)間的方式,那么我們想要對(duì)項(xiàng)目做編譯時(shí)間優(yōu)化涣达,就要找出來(lái)編譯耗時(shí)長(zhǎng)的部分在辆。
上文中提到了通過(guò) Xcode 查看項(xiàng)目具體編譯時(shí)間的方式,筆者也放了如下部分示意圖度苔。
三匆篓、減少項(xiàng)目編譯時(shí)間的考慮
1. 調(diào)整 Xcode 的Build Settings 中的配置
關(guān)于調(diào)整 Xcode 的 Build Settings 中的配置,筆者查詢資料后發(fā)現(xiàn)在 Xcode10 及之前調(diào)整空間比較大寇窑,在 Xcode11 的時(shí)候鸦概,筆者初步嘗試后,發(fā)現(xiàn)調(diào)整 Xcode 的 Build Settings 中的配置對(duì)于優(yōu)化項(xiàng)目編譯時(shí)間影響不大甩骏。
2. 把穩(wěn)定三方打包成 Framework
筆者在分析了項(xiàng)目編譯時(shí)間后窗市,發(fā)現(xiàn) QiShareDemo 中引入的每個(gè)三方都各自花費(fèi)了20s+的時(shí)間,記不清是查看了網(wǎng)上的文章示例還是如何饮笛,想到了如果在使用這些三方的過(guò)程中咨察,不會(huì)頻繁改動(dòng)這些三方源代碼的情況下,可以把這些三方打包成 Framework福青,嘗試解決編譯耗時(shí)久的問(wèn)題摄狱。
經(jīng)過(guò)嘗試把項(xiàng)目中的三方打成 Framework,供 QiShareDemo 使用后无午,就得到了一個(gè)明顯的減少編譯耗時(shí)的成效媒役。
從開(kāi)始的筆者在 clone 了 QiShareDemo 后,全量編譯編譯項(xiàng)目的編譯時(shí)間為105.207s宪迟;
后來(lái)經(jīng)過(guò)筆者初步把三方打包成 Framework 后酣衷,全量編譯項(xiàng)目的時(shí)間縮短為44.573s;
2.1 淺談編譯耗時(shí)縮短的原因
2.1.1 把穩(wěn)定三方打成 Framework 對(duì)編譯影響
可以結(jié)合上一篇文章淺談編譯過(guò)程來(lái)談這個(gè)問(wèn)題踩验。
關(guān)于項(xiàng)目直接使用 Framework 鸥诽,會(huì)減少編譯時(shí)間的原因,組內(nèi)同學(xué) 沐靈洛 和 奇舞647 都提及過(guò)箕憾,筆者推測(cè)原因是:
從編譯過(guò)程來(lái)看牡借,項(xiàng)目直接使用 Framework 相比使用 Cocoapods 的源代碼依賴,就省了預(yù)編譯袭异、詞法分析钠龙、語(yǔ)法分析、生成中間代碼、生成目標(biāo)文件的過(guò)程碴里。所以就減少了編譯時(shí)間沈矿。(編譯過(guò)程更多信息可查看 淺談編譯過(guò)程)
這部分還有一個(gè)劣勢(shì),組內(nèi)同學(xué) 大成小棧 提到說(shuō)咬腋,打成Framework 后在調(diào)試修改源代碼的時(shí)候就不方便了羹膳。這個(gè)是必然的,所以最好是把那些穩(wěn)定的三方打包成 Framework 根竿,或者是和組內(nèi)同學(xué)分工合作陵像,分別負(fù)責(zé)某個(gè)三方。
2.1.2 Objective-C 和 Swift 混編耗時(shí)影響
組內(nèi)同學(xué) 沐靈洛 還結(jié)合著筆者發(fā)出的編譯過(guò)程圖寇壳,提及過(guò)Swift 和 OC 項(xiàng)目混編相對(duì)于純 Swift 項(xiàng)目可能耗時(shí)更多的問(wèn)題醒颖。
這部分筆者的推測(cè)是看 Swift 項(xiàng)目的編譯過(guò)程。如果只是單純的 Swift 項(xiàng)目壳炎,編譯的前端過(guò)程用 Swift 編譯器就夠用了泞歉。
如果是Swift 和 OC 混編的項(xiàng)目,編譯的前端過(guò)程還會(huì)用到 Clang 匿辩,Clang 會(huì)把 C腰耙、Objective-C 的 API 向Swift API 做一個(gè)對(duì)應(yīng)。我想這個(gè)過(guò)程多少會(huì)比 Swift 編譯器單純編譯Swift 代碼多一些編譯耗時(shí)的增加撒汉。
下邊筆者放了一個(gè)Swift Compiler 架構(gòu)圖沟优,筆者是以流程圖的方式繪制制作的Swift Compiler 架構(gòu)圖。
注:在之前的文章 淺談編譯過(guò)程中筆者介紹了 GCC睬辐、LLVM編譯器挠阁,Swift 語(yǔ)言的編譯器是用的自有的Swift Compiler。
3. 使用工具查看項(xiàng)目中代碼編譯耗時(shí)
可以使用工具 BuildTimeAnalyzer-for-Xcode 查看項(xiàng)目中自己寫(xiě)的代碼的編譯時(shí)間溯饵。
筆者使用 BuildTimeAnalyzer-for-Xcode 查看了項(xiàng)目編譯時(shí)間侵俗,找出了2處編譯時(shí)間耗時(shí)的地方。
下圖是筆者使用 BuildTimeAnalyzer-for-Xcode 查看出的項(xiàng)目編譯時(shí)間耗時(shí)情況丰刊。
筆者在Target -> Build Settings -> Swift Compiler 的 Other Swift Flags 中添加了如下配置:
-Xfrontend -warn-long-function-bodies=100
-Xfrontend -warn-long-expression-type-checking=100
-Xfrontend -debug-time-function-bodies
上述配置內(nèi)容用于添加使用 BuildTimeAnalyzer-for-Xcode 的配置隘谣,用于查看出方法或表達(dá)式編譯耗時(shí)超過(guò)100ms的位置以警告的形式表現(xiàn)出來(lái)。
下邊筆者舉2個(gè)遇到的編譯耗時(shí)的代碼示例啄巧。
3.1 ??(nil-coalescing 空合并運(yùn)算符) 及 ”+“拼接在一起的耗時(shí)
這種 “??” 和 “+”拼接字符串用在一起時(shí)寻歧,在編譯過(guò)程中會(huì)比較耗時(shí)。最好改成短短的小代碼語(yǔ)句秩仆。
經(jīng)過(guò)筆者把上述耗時(shí)代碼使用 if let 的方式處理后码泛,編譯耗時(shí)的問(wèn)題已得到了解決。
3.2 使用 snapkit 時(shí)候可能遇到的編譯耗時(shí)
筆者打開(kāi)了測(cè)出的使用 Snapkit 的過(guò)程中澄耍,可能遇到的編譯耗時(shí)的代碼噪珊。檢測(cè)編譯耗時(shí)的示意圖如下:
如果把上述的紅色箭頭指向的代碼改成使用藍(lán)色箭頭指向的代碼可以解決編譯耗時(shí)的問(wèn)題晌缘。
筆者收獲是:使用Snapkit 布局的時(shí)候,參考值盡可能是一個(gè)明確值痢站,盡可能不要設(shè)置參考的時(shí)候磷箕,再讓編譯器去幫我們計(jì)算值,我們可以盡可能多的告訴編譯器我們知道的事情阵难。
四岳枷、其他考慮方向
1. SwiftUI
使用SwiftUI可以實(shí)時(shí)查看代碼顯示效果,并可以在不同設(shè)備上預(yù)覽效果呜叫。
使用 SwiftUI 可以提高開(kāi)發(fā)效率嫩舟。
SwiftUI 官方教程:Learn to Make Apps with SwiftUI
2. Swift的HotReload嘗試
考慮到市面上 Flutter 支持 HotReload 可以極大提升開(kāi)發(fā)效率,其實(shí)Swift 也支持 Hot Reload 怀偷,目前筆者只試過(guò) injectionIII Demo 的HotReload,目前不做過(guò)多介紹播玖。
Swift 的 HotReload 嘗試可以使用工具 Injection III 椎工。
如下網(wǎng)址中有 InjectionIII 的使用介紹及使用Demo。injectionIII
Injection III App Store下載地址:https://apps.apple.com/cn/app/injectioniii/id1380446739?mt=12