[譯]優(yōu)化 Swift 編譯時間

原文版本:Commits on Dec 11, 2017 ce6da1f3a47220259c3924df62f44f06bc45e222

翻譯:Yuen博客地址。如果對翻譯質(zhì)量存疑,歡迎提出問題建議)

Swift 不停在改進 ??。然而目前,對于中大型項目而言,漫長的編譯時間仍是一個巨大問題。這個倉庫的目的就是搜集相關 Tips,幫你減少項目的編譯時間。

???? 維護者:Arek Holko. 少了什么? 歡迎提 Issues 或者 PR!

Table of Contents

1、函數(shù)和表達式的類型檢測(Type checking of functions and expressions)

Build Settings --> Other Swift Flags 中加入

  • -Xfrontend -warn-long-function-bodies=100 (100 意味著 100 毫秒, 這個數(shù)字具體設置多少要依電腦配置和項目大小而定,建議多調(diào)整幾遍找到大小相對合適的數(shù)字,ps: 1 秒= 1000 毫秒)
  • -Xfrontend -warn-long-expression-type-checking=100

編譯后會看到如下圖所示的場景:
[圖片上傳失敗...(image-40c51f-1514117379893)]

?? Sources:

2、編譯緩慢的那些文件(Slowly compiling files)

上一段針對的是函數(shù)級別和表達式級別,現(xiàn)在我們關注整個文件的編譯時間
因為這里我們必須用 CLI 命令行界面來編譯項目,所以務必將參數(shù)設置正確了:

xcodebuild -destination 'platform=iOS Simulator,name=iPhone 8' \
  -sdk iphonesimulator -project YourProject.xcodeproj \
  -scheme YourScheme -configuration Debug \
  clean build \
  OTHER_SWIFT_FLAGS="-driver-time-compilation \
    -Xfrontend -debug-time-function-bodies \
    -Xfrontend -debug-time-compilation" | \
tee profile.log

上述代碼針對的是 .xcodeproj 的項目,如果項目是 .xcworkspace 的話,把上面第二代碼中的
-project YourProject.xcodeproj 替換成為 -workspace YourProject.xcworkspace。

然后從之前生成的 profile.log 文件中提取出編譯所需時間。

awk '/Driver Compilation Time/,/Total$/ { print }' profile.log | \
  grep compile | \
  cut -c 55- | \
  sed -e 's/^ *//;s/ (.*%)  compile / /;s/ [^ ]*Bridging-Header.h$//' | \
  sed -e "s|$(pwd)/||" | \
  sort -ReactNative | \
  tee slowest.log

成功執(zhí)行之后,就會得到一個 slowest.log 文件,內(nèi)容格式如下:

2.7288 (  0.3%)  {compile: Account.o <= Account.swift }
2.7221 (  0.3%)  {compile: MessageTag.o <= MessageTag.swift }
2.7089 (  0.3%)  {compile: EdgeShadowLayer.o <= EdgeShadowLayer.swift }
2.4605 (  0.3%)  {compile: SlideInPresentationAnimator.o <= SlideInPresentationAnimator.swift }

?? Sources:

3、Debug 時只編譯 active 架構(Build active architecture only)

默認就是這個設置,不過安全起見,可以去在 Build Settings --> Build active architecture only 確認一下
[圖片上傳失敗...(image-b98285-1514117379893)]

?? Sources:

4、生成 dSYM(dSYM generation)

新項目的默認設置是,Debug 配置編譯時不生成 dSYM 文件。但有時候為了在開發(fā)時進行 Crash 日志解析,會去修改這個參數(shù)。生成 dSYM 會消耗大量時間,可以去確認一下。

?? Sources:

5、Module 優(yōu)化(Whole Module Optimization)

另一個公認的方法是

  • 修改 Debug 配置 Build Settings --> Optimization LevelFast, Whole Module Optimization
  • 只在 Debug 配置添加 -Onone flag 到 Build Settings --> Other Swift Flags
    [圖片上傳失敗...(image-826b1e-1514117379893)]

這告訴了編譯器哪些東西?(譯者注:這里感覺自己的翻譯不到位,放原文吧)

It runs one compiler job with all source files in a module instead of one job per source file

Less parallelism but also less duplicated work

It's a bug that it's faster; we need to do less duplicated work. Improving this is a goal going forward

?? Sources:

6、CocoaPods 的 Module 優(yōu)化(Whole Module Optimization for CocoaPods)

如果使用 CocoaPods 的話,上一步 WMO 的配置也要考慮放到使用的 CocoaPods 項目中。
要實現(xiàn) WMO 配置,需要在項目的 Podfile 文件中添加如下的 post_install hook:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      if config.name == 'Debug'
        config.build_settings['OTHER_SWIFT_FLAGS'] = ['$(inherited)', '-Onone']
        config.build_settings['SWIFT_OPTIMIZATION_LEVEL'] = '-Owholemodule'
      end
    end
  end
end

7、第三方依賴(Third-party dependencies)

在項目中有兩種途徑可以引入第三方依賴:

  1. 源碼形式,在你每次 clean 項目編譯內(nèi)容的時候都會都會重新編譯,例如:CocoaPods,git submodules, 復制粘貼的 code, 應用 target 依賴的子項目(subprojects)形式
  2. 提前編譯好的 framework/library形式,例如:Carthage, 第三方不透露源碼、提供的靜態(tài)庫

因此在你每次 clean build 之后,CocoaPods 大多情況下會重新編譯,導致大量的編譯時間花銷。

Carthage 雖然難用一些,但當你很在意編譯時間的話卻不失為一個好選擇。只有當你在更新依賴列表(添加新 framework,更新 framework 的新版本)的時候,你才會去編譯外部依賴。Carthage 也許需要你花 5-15 分鐘的時間去完成,但相比使用 CocoaPods 做依賴,單從長遠的編譯時間花銷來看,Carthage 或許會節(jié)省不少時間。

?? Sources:

  • time spent waiting for Xcode to finish builds ??

8、模塊化(Modularization)

Swift 的增量編譯并不完美。有時一些增量編譯中,也許僅僅是修改了一個字符串,就會導致整個項目重新編譯。這是一個亟待解決的問題。

為了避免這個問題,你可以考慮將 app 拆分為一個個模塊。在 iOS 里,有2中方案:動態(tài)庫和靜態(tài)庫(Xcode9 Beta4 版本開始支持 Swift 靜態(tài)庫)。

假設你的 app 依賴一個叫做 DatabaseKit 的內(nèi)部 framework。模塊化的方法能夠保證在你對 app 項目做了一些修改時,DatabaseKit 不會因為這個增量編譯的行為而重新編譯。

?? Sources:

9、XIBs

代碼 和 XIBs/Storyboards 的取舍一直是個熱門話題。不過我們這里只是片面的談一談這個問題。這個情況很有趣:當你在 IB 中做了一些改動時,只有這個 IB 文件被編譯了(成為 NIB 格式);與之成鮮明反差的是,有時候當你在 UIView 的一個子類中修改了一行代碼,Swift 編譯器可能會重新編譯項目中的很大一部分代碼。

?? Sources:

10、Xcode Schemes

假設我們有一個常見設置的項目,它有3個 target:

  • App
  • AppTests
  • AppUITests

只在一個 scheme 上工作沒有問題,但是我們還可以優(yōu)化。下方的配置是我們一直在使用的,包了3個 scheme:

App

?+B 只會編譯這個 app。只跑單元測試不跑 UI 測試。 對于 short iterations 很有用, 比如在 UI 代碼上, 因為只有需要用到的代碼被編譯了。

[圖片上傳失敗...(image-59dd50-1514117379893)]

App - 單元測試工作流(App - Unit Test Flow)

編譯內(nèi)容會包含這個 app 和單元測試 target。運行的話,只會跑單元測試。在涉及到單元測試的代碼時很有用,因為只要一編譯完項目,就能立即發(fā)現(xiàn)在測試里的編譯錯誤了。甚至不需要去運行他們。

當你的 UI 測試需要話費很久的時候,這個Scheme很有用。

[圖片上傳失敗...(image-efc09e-1514117379893)]

App - 所有測試工作流(App - All Tests Flow)

編譯應用和所有 target。跑所有測試用例。當涉及到那些和 UI 關系緊密包含 UI 測試的代碼時作用較大。

[圖片上傳失敗...(image-7e5e00-1514117379893)]

?? Sources:

11、使用全新的 Xcode 編譯系統(tǒng)(Use the new Xcode build system)

在 Xcode 9 蘋果 介紹了一種新的 Xcode 編譯系統(tǒng). 這還只是“預覽”版本,默認并沒有開啟。這個新系統(tǒng)比默認的原有的編譯系統(tǒng)快的多。
如果想要使用它,到 Xcode 的 File 菜單進入Workspace 或 Project Settings 的頁面,就可以切換到新的編譯系統(tǒng)了。
[圖片上傳失敗...(image-577790-1514117379893)]

?? Sources:

12、啟用 Concurrent Swift Build Tasks(Enable Concurrent Swift Build Tasks)

Xcode 9.2 對于增加 Swift 項目的 concurrent build tasks 有一個實驗性質(zhì)的支持。對于一些項目,這個特性可能會大大改善編譯時間。另外要注意,當啟用這個選項的時候,Xcode 可能會增加大量內(nèi)存開銷。

如果要啟用這一特性,退出 Xcode,然后在 Terminal 窗口中輸入以下命令:

$defaults write com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively -bool NO

測試以下這個改動對你的項目編譯產(chǎn)生了什么影響。對于很多項目來說,這不會導致什么變化;但是對另外一些,這個改動非常重要。如果要棄用這個特性的話,在 Terminal 窗口中輸入以下命令,然后重啟 Xcode:

$defaults delete com.apple.dt.Xcode BuildSystemScheduleInherentlyParallelCommandsExclusively

(譯者注:為什么是設為 NO 而不是 YES,開發(fā)者在 推特上 說是當時寫錯了??。值得注意的是,根據(jù)這里所說,開啟這個新特性的操作,只會影響原有的默認編譯系統(tǒng) standard build system;新的 build system 已經(jīng)啟用這一特性。

?? Sources:

13、在 Xcode 中顯示編譯時間(Showing build times in Xcode)

最后,為了能夠準確知道你的編譯時間是否改善了,你應該在 Xcode 的 GUI 界面中顯示時間。在命令行中運行:

$ defaults write com.apple.dt.Xcode ShowBuildOperationDuration -bool YES

成功之后,在 ?+B 編譯一個項目后你會看到:
[圖片上傳失敗...(image-a28378-1514117379893)]

建議每次都在一個相對公平的環(huán)境下比較編譯時間,比如:

  1. 退出 Xcode
  2. 清理 Derived Data ($ rm -rf ~/Library/Developer/Xcode/DerivedData)
  3. 打開 Xcode 中的項目
  4. 在 Xcode 打開或者完成索引階段(indexing phase)后,立刻開始編譯。因為使用 Xcode 9 編譯也會執(zhí)行索引,所以 The first approach 看起來更具代表性。(The first approach seems to be more representative because starting with Xcode 9 building also performs indexing)

另外,你也可以利用命令行統(tǒng)計編譯時間:

$ time xcodebuild other params

?? Sources:

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 用到的組件 1、通過CocoaPods安裝 2、第三方類庫安裝 3、第三方服務 友盟社會化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 15,199評論 1 180
  • 七年以來,我最大的苦難便是華麗麗的遇你又同樣華麗麗的失去。 ...
    426c8c5ec569閱讀 304評論 0 0
  • 很濃重的霾,早晨醒來就發(fā)覺自己深中霾伏。然后是各種不適,嗓子不舒服,出門戴著口罩,都會不舒服,腦袋暈暈的一天,...
    遺世Caroline閱讀 221評論 0 0
  • 因寒假遇上春節(jié),我們的帥哥老師要回家探親過節(jié),完美天籟合唱團從1月份開始放假,至今一個多月了,今晚終于又開始上課,...
    葉瀅YeYing閱讀 429評論 4 3
  • 流光聽得見,說“我愛你”的甜言。 銘記你于心尖,心只為你執(zhí)著不變。 ??菔癄€的諾言,(只為你說)(只要你說)都不厭...
    BULABULA小八閱讀 212評論 0 1

友情鏈接更多精彩內(nèi)容