關於Xcode編譯性能優化的研究工作總結

近來(8月1–8月12)結合Xcode的官方文檔和網上資料經驗對Xcode的一些配置選項進行了編譯優化的嘗試研究,所謂優化主要從編譯耗時及編譯出的安裝包大小進行優化。在研究分析過程中將手上的幾個Demo項目進行了編譯測試,有Swift項目也有Object-C項目。此外,對於不同配置的相應原理也做了較深入的挖掘分析。

總的來說,對Xcode的Build Setting 進行配置選項的修改是最直接的編譯設置。本工作總結除了從Xcode本身的配置進行優化以外,還從外部環境、Xcode插件以及外部硬件配置的編譯優化進行了研究分析。


目錄


一、編譯時長優化 Swift編譯優化 Find Implicit Dependencies 
二、編譯時長優化 Architectures 
三、編譯時長優化 Precompile Prefix Header 預編譯頭文件 
四、編譯時長優化 Swift Compile - Code Generation Optimization Level 
五、加載RAM磁盤編譯Xcode項目 
六、編譯線程數和Debug Information Format 
6.1、 提高XCode編譯時使用的線程數 
6.2、 將Debug Information Format改爲DWARF 
七、Link-Time Optimizations 鏈接時優化 
八、加裝SSD固態硬盤 
九、安裝包大小優化 Asset Catalog Compiler - Options Optimization 
十、安裝包大小優化 Flatten Compiles XIB Files 
十一、安裝包大小優化 清理未被使用的圖片資源LSUnusedResources 
十二、安裝包大小優化 Deployment Postprocessing和Strip Linked Product 
十三、安裝包大小優化 Linking->Dead Code Stripping 
十四、Injection for Xcode 高效Xcode編譯調試插件 
14.1 Injection 
14.2 Limitations of Injection(侷限性)

一、編譯時長優化 Swift編譯優化 Find Implicit Dependencies

對所編譯項目的Scheme進行配置 
Product > Scheme > Edit Scheme > Build 
Build Opitions選項中,去掉Find Implicit Dependencies. 
這裏寫圖片描述

原理: 
選中Find Implicit Dependencies時,編譯以下內容: 
* 項目所有的文件 
* 被修改的frameworks文件 

未選中Find Implicit Dependencies時,編譯以下內容: 
* 項目中必要的文件 
* 不會重新編譯frameworks文件,即時你對其中的文件做了修改

Test: 
對不同設置下(是否選中Find Implicit Dependencies)的項目編譯時間進行比較。 
注:每次編譯前 進行clean操作(shift + command + k),達到消除Xcode自身增量編譯帶來的干擾。

Result: 
對手頭的兩個demo進行了編譯耗時的比較: 
這裏寫圖片描述

對於兩個不同的項目,該配置所帶來的編譯優化效果並不一定都能體現。 
這裏寫圖片描述

對兩個工程的framework文件進行對比之後發現,LoveFreshBeen的framework文件要比DXDoctor的少得多。所以應用該配置時,DXDoctor編譯時所反映出來的效果會更明顯。

缺點分析:
在這個選項(Find Implicit Dependencies)被選中的情況下,即使你只是對項目進行了很細微的
改變,項目中的所有資源文件都會被重新編譯一遍。也會對所有被改變的frameworks進行編譯。沒有選
中這個選項時,只會對文件中的一些Swift文件進行編譯,編譯耗時會顯著的下降。只是,在這種模式下,
你對frameworks中的文件所進行的修改將不會進行重新編譯。
結論:
視修改的項目文件的不同,對兩種Scheme進行選擇,擇一使用以提高編譯性能。

參考:Swift Slow Compile Times Fix


二、編譯時長優化 Architectures

在Build Settings中,有個Architectures配置選項。 
這裏寫圖片描述 
Architectures 
是指定工程支持的指令集的集合,如果設置多個architecture,則生成的二進制包會包含多個指令集代碼,提及會隨之變大。

Valid Architectures 
有效的指令集集合,Architectures與Valid Architectures的交集來確定最終的數據包含的指令集代碼。

Build Active Architecture Only 
指定是否只對當前連接設備所支持的指令集編譯,默認Debug的時候設置爲YES,Release的時候設爲NO。Debug設置爲YES時只編譯當前的architecture版本,生成的包只包含當前連接設備的指令集代碼;設置爲NO時,則生成的包包含所有的指令集代碼(上述的V艾力達Architecture與Architecture的交集)。所以爲了更快的編譯速度,Debug應設爲YES,而Release應設爲NO。

注:Debug設置爲YES時,如果連接的設備是arm64的(iPhone 5s,iPhone 6(plus)等),
則Valid Architecture中必須包含arm64,否則編譯會出錯。這種模式下編譯出來的版本是向下
兼容的,即:編譯出的armv6版本可在armv7版本上運行。

參考:蘋果官方“Xcode Build Setting Reference” 
關於Xcode “Build Setting”中的Architectures詳解


三、編譯時長優化 Precompile Prefix Header 預編譯頭文件

Build Setting > Apple LLVM 7.1 - Language 
這裏寫圖片描述 
Xcode 6及之後版本默認不使用pch文件參與項目編譯,原因有二: 
* 去掉自動導入的系統框架類庫的頭文件們可以提高源文件的複用性,便於遷移; 
* 一個龐大的Prefix Header會增加Build耗時。

但對於原有項目應用了pch文件的情況,就需要對Xcode的Build Setting進行配置以使用pch。

當Precompile Prefix Header設爲NO時,頭文件pch不會被預編譯,而是在每個用到它導入的框架類庫中編譯一次。每個引用了pch內容的.m文件都要編譯一次pch,這會降低項目的編譯速度。

將Precompile Prefix Header設爲YES時,pch文件會被預編譯,預編譯後的pch會被緩存起來,從而提高編譯速度。 
需要編譯的pch文件在Prefix Header中註冊即可。

手動創建pch文件: xcode6中如何添加pch文件 
參考 :Xcode Precompile Prefix Header淺析 
Why isn’t ProjectName-Prefix.pch created automatically in Xcode 6?

四、編譯時長優化 Swift Compile - Code Generation Optimization Level

Build Setting > Swift Compile - Code Generation > Optimization Level 
這裏寫圖片描述 
Swift 編譯優化選項,對手上的兩個demo進行了以下測試: 
這裏寫圖片描述

Debug None[-Onone] Release Fast[-O] 是Xcode在Debug模式下編譯Swift項目的最優選項,通過測試可以看出,在默認配置情況下和自定義情況下的編譯耗時存在比較明顯的差異。


五、加載RAM磁盤編譯Xcode項目

DerivedData

Xcode會在文件系統中集中的緩存臨時信息。

每次對Xcode iOS項目進行clean、build或者在iOS虛擬機上launch,Xcode都會在DeriveData文件夾中進行讀寫操作。換句話說,就是將Derived Data的讀寫從硬盤移動到內存中。 
DeriveData文件夾中包含了所有的build信息、debug- 和 release- built targets以及項目的索引。當遇到零散索引(odd index)問題(代碼塊補全工作不正常、經常性的重建索引、或者運行項目緩慢)時,它可以有效地刪除衍生數據。刪除這個文件夾將會導致所有Xcode上的項目信息遭到破壞。

Step 1 
將DeriveData下的文件刪除:

 

C代碼  收藏代碼
  1. rm -rf ~/Library/Developer/Xcode/DerivedData/*  
 

 

C代碼  收藏代碼
  1. hdid -nomount ram://4194304  

 刪除的這些數據,Xcode會在Build時重新寫入的。

Step 2 
在~/Library/Developer/Xcode/DerivedData.上部署安裝2 GB大小的RAM磁盤。 
進到~/Library/Developer/Xcode/DerivedData.

 

C代碼  收藏代碼
  1. cd ~/Library/Developer/Xcode/DerivedData  
 

 

創建2 GB的RAM磁盤(size的計算公式 size = 需要分配的空間(M) * 1024 * 1024 / 512):

C代碼  收藏代碼
  1. hdid -nomount ram://4194304  

 

此行命令後將會輸出RAM磁盤的驅動名字:/dev/diskN(N爲數字)。

初始化磁盤:

C代碼  收藏代碼
  1. newfs_hfs -v DerivedData /dev/rdiskN  

 

有以下輸出: 
   Initialized /dev/rdisk3 as a 2 GB case-insensitive HFS Plus volume

安裝磁盤:

C代碼  收藏代碼
  1. diskutil mount -mountPoint ~/Library/Developer/Xcode/DerivedData /dev/diskN  

 

這會在已存在的DeriveData上安裝一個卷,用於隱藏舊的文件。這些文件仍會佔據空間,但在移除RAM磁盤之前都無法訪問。

在重啓或從Finder中彈出RAM磁盤時,磁盤中的內容將會消失。下次再創建磁盤時,Xcode將會重新構建它的索引和你的項目中間文件。

創建虛擬磁盤後, 並不是直接佔用掉所有分配的空間, 而是根據虛擬磁盤中的文件總大小來逐漸佔用內存. 

注:如果創建的虛擬磁盤已滿, 會導致編譯的失敗. 此時清除掉Derived Data後重新編譯, 就算有足夠的空間也還是有可能會導致編譯失敗. 重啓Xcode可以解決此問題.

對手頭Demo進行編譯測試,由於編譯本身讀寫內容較少,耗時較短,都在10s到20s之內,所以提速感覺不明顯,在1s到2s間(10%左右),也許應用到較大的項目中會有比較好的體現。

參考: Reduce XCode build times 
【iOS Tip】提高Xcode編譯速度


六、編譯線程數和Debug Information Format

6.1、 提高XCode編譯時使用的線程數

C代碼  收藏代碼
  1. defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 8    

 

其後的數字爲指定的編譯線程數。XCode默認使用與CPU核數相同的線程來進行編譯,但由於編譯過程中的IO操作往往比CPU運算要多,因此適當的提升線程數可以在一定程度上加快編譯速度。


6.2、 將Debug Information Format改爲DWARF

在工程對應Target的Build Settings中,找到Debug Information Format這一項,將Debug時的DWARF with dSYM file改爲DWARF。

這一項設置的是是否將調試信息加入到可執行文件中,改爲DWARF後,如果程序崩潰,將無法輸出崩潰位置對應的函數堆棧,但由於Debug模式下可以在XCode中查看調試信息,所以改爲DWARF影響並不大。

需要注意的是,將Debug Information Format改爲DWARF之後,會導致在Debug窗口無法查看相關類類型的成員變量的值。當需要查看這些值時,可以將Debug Information Format改回DWARF with dSYM file,clean(必須)之後重新編譯即可。

注:6.2 的解決方案爲Xcode的默認設置,進行反向設置時,編譯速度改變不大;

參考:To speed up the XCode compile and link speed (200%+)


七、Link-Time Optimizations 鏈接時優化

Apple LLVM 7.1 - Code Generation Link-Time Optimization 
這裏寫圖片描述

Link-Time Optimization執行鏈接時優化(LTO)。在Clang/LLVM領域,這意味着鏈接器獲得的是LLVM字節碼,而不是通常的目標文件。這些字節碼在一種更抽象的層次上代表程序這裏寫鏈接內容的執行過程,允許LTO得以進行,但是壞處是,仍然需要將他們轉換成機器代碼,在鏈接時需要額外的處理時間。

參數設爲YES時,能夠優化鏈接時間;目標文件以LLVM二進制文件格式存儲,在鏈接期間,優化了整個程序。

將其設爲NO時,可以減少Link階段的時間。對於Link階段耗時較長的項目,整體編譯優化體現較爲明顯。


八、加裝SSD固態硬盤

固態硬盤傳輸速度能達到500MB/s,其中讀取速度達到400-600MB每秒,寫入速度達到200MB每秒。而傳統硬盤讀取速度極限也無法超越200MB每秒,寫入速度在100MB每秒左右。如果遇到非連續的散片數據,SSD能體現出極快的讀寫速度。而傳統機械硬盤由於磁頭尋道等原因,傳輸速度偏慢。

SSD加快了程序的I/O速率,讀寫速度比普通硬盤快,從而提升Xcode的編譯速度。受限於各種硬件原因,沒有進行測試。

參考: SSD 硬盤能否明顯加快編譯的速度? 
固態硬盤的好處,固態硬盤與普通硬盤的區別


九、安裝包大小優化 Asset Catalog Compiler - Options Optimization

Build Setting > Asset Catalog Compiler - Options
 
這裏寫圖片描述 
在Optimization 優化設置項有三個選項,不指定、time和Space。 
這裏寫圖片描述

Optimization nothing是Xcode默認的設置。 
與預想的不同,在選擇Optimization time 時,編譯時長並沒有得到優化。 
但在Optimization space時,編譯耗時基本沒有波動,但編譯生成的app 大小有不小程度的優化。


十、安裝包大小優化 Flatten Compiles XIB Files

是否扁平化編譯XIB文件。 
這裏寫圖片描述 
官方解釋是:指定是否在編譯時剝離nib文件以優化它們的大小,設爲YES時編譯出來的nib文件會被壓縮但是不能編輯。

Description: Boolean value. Specifies whether to strip a nib files to 
reduce their size. The resulting nib file is more compact but is not 
editable.

這裏寫圖片描述

測試app大小的同時也對編譯耗時進行了測試,在兩種編譯模式下的編譯耗時基本沒有變化。

參考:What does the “Flatten compiled xib files” project build option “do” 
官方文檔 Interface Builder Compiler Build Settings


十一、安裝包大小優化 清理未被使用的圖片資源LSUnusedResources

這裏寫圖片描述 

項目的開發過程總是會經歷較長期的迭代,不斷的添加功能的同時會引入大量的圖片資源。需求變更、業務邏輯修改等需要移除某些功能模塊時就會導致這些前期加入的圖片資源問價被忽略而遺留在編譯的安裝包中,長此以往會使得安裝包變得格外臃腫。特別是類似於手Q項目的開發,開發人員多,產品迭代頻繁,開發時間緊俏,開發人員輪換等特點更有可能導致這樣的後果。

一個較爲傳統的清理方法時將圖片資源的文件名一一複製粘貼到Xcode的全局變量查找中去查找該字符串,如果返回的結果爲零,則該資源很有可能沒被使用。之所以是“很有可能”,是因爲在代碼中,資源有時是通過字符串拼接的方式進行引用的。

在這裏提供一個github上的開源工具 LSUnusedResources ,這個工具是對github上的另一個開源工具Unused的優化改進(匹配速度、結果準確性),作者針對源碼、Xib、Storyboard 和 plist 等文件,先全文搜索其中可能是引用了資源的字符串,然後用資源名和字符串做匹配,從而找出未被使用的資源,比Unused的查找速度要快得多。

使用起來也比較簡單: 
1、將工程目錄路徑拷貝到Folder或通過Browse瀏覽文件目錄; 
2、在Resource指定要查找的資源類型; 
(經過本人測試,發現該工具在未指定Resource類型時所查找出來的資源不是很準確,列舉出 的資源事實上是正在使用的,所以我在測試時指定查找了png類型的文件。) 
3、單擊Search以查閱結果。

注:爲了避免對資源的誤刪操作,建議在該工具輸出結果後對結果中的資源名複製並在Xcode的全局查找
中進行校驗。

下載安裝:LSUnusedResources.app.zip 
Github地址:LSUnusedResources 
參考鏈接:查找XCode工程中沒被使用的圖片資源


十二、安裝包大小優化 Deployment Postprocessing和Strip Linked Product

Xcode中Strip Linked Product 的默認設置爲YES,但是Deployment Postprocessing的默認設置爲NO。在Deployment Postprocessing 是Deployment的總開關,所以在打開這個選項之前 Strip Linked Product是不起作用的。

注:當Strip Linked Product設爲YES的時候,運行app,斷點不會中斷,在程序中打印[NSThread 
callStackSymbols]也無法看到類名和方法名。而在程序崩潰時,函數調用棧中也無法看到類名和方法名。

這裏寫圖片描述

打開這兩個選項之後進行編譯,編譯出的安裝包大小有了較大程度的優化: 
這裏寫圖片描述

參考:Xcode中和symbols有關的幾個設置


十三、安裝包大小優化 Linking->Dead Code Stripping

將Dead Code Stripping 設置爲YES 也能夠一定程度上對程序安裝包進行優化,只是優化的效果一般,對於一些比較小的項目甚至沒有什麼優化體現,所以這裏也就沒有上測試數據。

Dead Code Stripping 是對程序編譯出的可執行二進制文件中沒有被實際使用的代碼進行Strip操作。

對於更深層次的解讀,在參考鏈接的文章裏有詳細描述。 
參考:Dead Code Stripping


十四、Injection for Xcode 高效Xcode編譯調試插件

14.1 Injection

github上的開源項目,Xcode插件。

對於iOS開發者來說,XCode有個另人十分難耐的特性——編譯時長的問題。也許工作的時候你能夠爲自己找到一個閒下來喝杯咖啡的正當的藉口,然而,多次的調試編譯過程足以讓你喝上好多杯咖啡了。應該說,Injection是iOS開發者的福音,它在很大程度上優化了XCode的性能,提升了開發者的工作效率。

Injection能夠在app運行時動態地向Swift或者OC文件注入新代碼並且即時地呈現在運行中的模擬器的app上,從而達到提高程序編譯速度,提高開發效率的目的。開發者不需要重新編譯重新運行整個項目,這樣的優化使得編譯週期從7秒縮短至1秒。從XCode的輸出臺來看,每次在進行代碼注入之後都只會編譯被注入了代碼的文件。這麼一聽有點類似於增量編譯。

設想這樣一個場景,對於一個編譯啓動需要10分鐘的項目,如果你想對某個功能的動畫效果進行微調,是否意味着你需要以至少10分鐘爲一個調試周期去對你的改動進行測試,而injection則能夠在程序運行時動態的改動方法實現,並呈現在模擬器或真機上。

Injection Github https://github.com/johnno1962/injectionforxcode ; 
或者到這裏去看看他的演示:https://www.youtube.com/watch?v=uftvtmyZ8TM

對於Injection的安裝使用,可以到第一個鏈接裏下載package。Injection團隊爲開發者準備了一套傻瓜式的配置流程,基本上都是單擊continue就行了,然後重啓你的Xcode。裝成功後你會看到product > injection plugin。此時你應該已經裝成功了。點擊 Product >Injection Plugin > Patch Project for Injection 選項, 之後插件會在main.m 中插入兩段代碼。

C代碼  收藏代碼
  1. #ifdef DEBUG  
  2. static char _inMainFilePath[] = __FILE__;  
  3. static const char *_inIPAddresses[] = {"10.12.1.67""127.0.0.1", 0};  
  4.   
  5. #define INJECTION_ENABLED  
  6. #import "/tmp/injectionforxcode/BundleInjection.h"  
  7. #endif  

 

這不會影響程序原有代碼,如果要還原,隨時可以通過點擊 Revert Injection’s Changes 選項來還原。你可以開搞了。

用一個demo做實驗,將project運行起來,在運行時對你的代碼進行改動,可以使用快捷鍵Ctrl + =快速運行。也可以在 product > injection plugin > inject and reset app。 你會發現你改動的代碼所在類的左上角有一個藍色的進度條,一秒不到的時間就能夠完成注入並運行在你的app上。當然,你也能夠在你改動的代碼的方法裏邊加上一個斷點,快捷鍵Ctrl + = ,你會發現運行時會停在你設定的breakpoint上。

對於Swift文件injection好像還不能做到完美支持,github上有相關的解釋,我還沒有深入的嘗試,有興趣的童鞋可以去看看,順便交流交流。 
injection是Xcode IDE的一個擴展,允許你去對類的一個方法實現打補丁而不需要重啓app。官方的原理如下:

It performs this by parsing the build logs of the application to 
determine how a source file was last compiled. With this it wraps the 
result of re-compiling into a bundle which is injected into the 
application using the dynamic loader. At this point there are two 
versions of a class in the app, the original and a new modified 
version from the bundle. The modified version is then “swizzled” onto 
the original class so changes take effect.

(個人翻譯)它通過解析程序的編譯日誌來確定最後一次編譯的源文件。通過動態加載程序把重新編譯的結果打包到被注入代碼的app中。此時有兩個版本的類應用,最初的和一個新的修改版本的包。這個修改後的版本,被“swizzled到”原始類中而生效。

除此之外,injection插件還有一個參數調節器Tunable Parameters,對於UI開發來說是個利器。比如對顏色的確定,對字體大小的界定等等。運行app,然後對參數進行修改就能夠動態的進行調試了。直觀而且方便。 
這裏寫圖片描述 
對於 Tunable Parameters的使用我還沒有涉足,它的使用目前僅限於Swift項目,還需要在項目中進行一些諸如添加頭部代碼的配置,有興趣的童鞋可以到這裏瞭解: 
https://github.com/johnno1962/injectionforxcode/blob/master/documentation/tunable_parameters.md 

其實也不復雜,就是在新建一個main.m文件之後加上幾行代碼。 
在使用injection時,一個新的Xcode項目文件將會在原本項目的文件裏生成(iOSInjectionProject或OSXInjectionProject)。這個文件是用於存放那些被injecte的項目文件的,建議將其加入到.gitignore 中,直接忽略。

每一次的項目文件被injected,在injection項目目錄裏的injectionCount.txt中的數字就會增加。它可以很直觀的告訴你通過injection進行了多少的文件改動。

如果你想在真機或Appcode上進行測試: 
你需要做一些輕量級的配置:在你的main.m文件加上如下幾行代碼:

C代碼  收藏代碼
  1. #ifdef DEBUG  
  2. static char _inMainFilePath[] = __FILE__;  
  3. static const char *_inIPAddresses[] = {"10.12.1.67""127.0.0.1", 0};  
  4.   
  5. #define INJECTION_ENABLED  
  6. #import "/tmp/injectionforxcode/BundleInjection.h"  
  7. #endif  

 

這個配置也可以通過Product > Injection Plugin > Patch Project For Injection 來進行自動配置。對於Swift文件,你需要添加一個空的main.m文件來完成配置。

至於使用Appcode的盆友,可以上github上看看教程: 
https://github.com/johnno1962/injectionforxcode


14.2 Limitations of Injection(侷限性)

貼github原文:

There are limitations of course, largely centering around static 
variables, static or global functions and their Swift equivalents. 
Consider the following Objective-C code. 
這裏寫圖片描述

  • One potential problem is when the new version of the class is 
    loaded, it comes with it’s own versions of static variables such as 
    sharedInstance and the once token. After injection has occurred, this 
    would generate a new singleton instance.

To prevent this, class methods with the prefix “shared” are not 
swizzled on injection to support this common idiom.

  • It can be tough to look through all of the memory of a running 
    application. In order to determine the classes and instances to call 
    the injected callbacks on, Injection performs a “sweep” to find all 
    objects in memory. Roughly, this involves looking at an object, then 
    recursively looking through objects which it refers to. For example, 
    the object’s instance variables and properties.

    This process is seeded using the application’s delegate and all windows. Once all the in-memory reference are collected, Injection 
    will then filter these references to ones that it has compiled and 
    injected. Then sending them the messages referenced in the callbacks 
    section.

    If no references are found, Injection will look through all objects that are referred to via sharedInstance. If that fails, well, 
    Injection couldn’t find your instance. This is one way in which you 
    may miss callbacks in your app.

  • The function dispatch_on_main does not inject, as it has been 
    statically linked into the application. It does however, inject by 
    proxy in the case shown via the doSomething method. dispatch_on_main 
    will have been linked locally to a version in the object file being 
    injected.

injection作爲Xcode的插件,還是有侷限性的。 
injection的作用域主要集中在靜態變量、靜態或全局函數及其Swift的當量(按:Swift equivalents)。

以下是作者貼的示例代碼: 
這裏寫圖片描述 
1)有一個潛在的問題,當類的新版本被加載,它帶有自己的靜態變量版本sharedInstance和once標記。發生injected後,將產生一個新的單一實例。

  To prevent this, class methods with the prefix "shared" are not swizzled on 
injection to support this common idiom.       
  以上這句我捉摸了很久還是沒有吃透。

2)它可以瀏覽所有的正在運行的應用程序的內存。爲了確定類和實例能夠調用injectied的回調,injection會執行一次“掃描”,找到在內存中的所有對象。粗略說,這涉及了一個對象,然後通過遞歸尋找它所指向的對象。例如對象的實例變量和內容(properties)。

3)This process is seeded using the application’s delegate and all windows.(按:這個過程通過應用程序的代理和所有的窗口)。一旦所有在內存中的引用被收集,injection將會過濾這些它已經編譯和injected的引用,。然後再將被引用信息的回調部分發送出去。

4)如果沒有找到引用注入的內容,Injection將通過sharedInstance查找所有被涉及到的對象。如果沒有找到任何對象,那麼,Injection將找不到你的實例。這會導致你無法在你的app中進行回調函數的調用。

5)函數dispatch_on_main無法被injected,因爲它已被靜態地鏈接到應用程序。但是,injection可以通過代碼示例裏的doSomething方法進行inject。dispatch_on_main將會被鏈接到本地的在被injected對象文件的一個新版本中。

以上內容參考:https://github.com/johnno1962/injectionforxcode

對於某些童鞋的疑問:injection的編譯效率與XCode自身的增量編譯有什麼優勢?我已經在github上Issue了作者並得到了如下回復: 

這裏寫圖片描述 

但是具體到底能夠提升多少,這個有待進一步的測試。 



轉載自:http://815222418.iteye.com/blog/2317439

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章