原文:https://juejin.im/post/5cf01822e51d45777a126125
開啟 Cocoapods 新選項,加快項目索引速度
前幾天 Cocoapods 1.7.0 正式版發(fā)布了,我最期待的一個功能是 Multiple Pod Projects,昨天順手就給接入了,項目解析和索引效率有了非常明顯的提升,過程中踩了些坑,這次一起把之前 debug 的經(jīng)驗分享一下。
generate_multiple_pod_projects 選項
之前 Cocoapods 會把每個依賴作為 target 放到 Pods 項目里,但 xcodeproj 本身的編碼不太能適應(yīng)這種情況,在引入幾十個 pod 的情況下,項目解析的效率會急劇下降。
以我公司其中一個主項目為例,Pods 項目的大小達到了 5.2 MB(這可都是純文本),在第一次打開項目,解析項目構(gòu)建索引時,就能明顯聽到風(fēng)扇開始狂轉(zhuǎn),這個過程會持續(xù)好幾分鐘才會結(jié)束。
Cocoapods 這次更新引入了一個 generate_multiple_pod_projects 的選項,可以讓每個依賴都作為一個單獨的項目引入,大大增加了解析速度:

開啟的方式很簡單,只要在 Podfile 里加入這一行就可以了:
install! 'cocoapods', generate_multiple_pod_projects: true
復(fù)制代碼
拆分后每個項目的大小都差不多是 40 - 100 kb 左右:

這個選項開啟之后的效果非常顯著,我在 Xcode 里執(zhí)行了 clean,之后 indexing 的過程在幾秒鐘里就結(jié)束了,而且風(fēng)扇也沒有狂轉(zhuǎn)。
至于為什么這樣可以提升項目的解析速度,我大概看了一下 xcodeproj 的編碼,所有的 Item 都會按照類別存放到各自的 section 里,最終在項目的結(jié)構(gòu)樹里會以引用的形式呈現(xiàn)。
所以文件引用查找的范圍是所有 Pod 引用庫的文件的集合,而每次索引的構(gòu)建都至少會遍歷一次項目樹,這就會導(dǎo)致索引時間的暴增,除此之外單個龐大的項目解析也不利于多線程執(zhí)行,拆分成多個項目的話就能有效地解決這些問題。
install! 函數(shù)只能調(diào)用一次
需要注意 install! 是個用來配置的函數(shù),由于之前我還開啟了另一個選項,所以接入時是這么做的:
install! 'cocoapods', generate_multiple_pod_projects: true
install! 'cocoapods', disable_input_output_paths: true
復(fù)制代碼
但是這么做之后發(fā)現(xiàn)不生效,后來才想起來 install! 是一個用來配置的函數(shù),重復(fù)調(diào)用的話,只會以最后一次的調(diào)用為準(zhǔn)。所以應(yīng)該在一次調(diào)用里把它們都傳入進去:
install! 'cocoapods',
disable_input_output_paths: true,
generate_multiple_pod_projects: true
復(fù)制代碼
Swift 版本控制
另一個坑就是在 post_install 時,為了一些版本的兼容,需要遍歷所有 target,調(diào)整一部分庫的 Swift 版本:
post_install do |installer|
swift_4_0_compatible = [ ... ]
swift_4_2_compatible = [ ... ]
installer.pod_targets.each do |t|
t.build_configurations.each do |c|
c.build_settings['SWIFT_VERSION'] = '4.0' if swift_4_0_compatible.include? t.name
c.build_settings['SWIFT_VERSION'] = '4.2' if swift_4_2_compatible.include? t.name
end
end
end
復(fù)制代碼
但是如果開啟了 generate_multiple_pod_projects 的話,由于項目結(jié)構(gòu)的變化,installer.pod_targets 就沒辦法獲得所有 pods 引入的 target 了。
Podfile 里的代碼如何 debug
查了 Xcodeproj 和 Cocoapods 的文檔之后我都沒有得到很好的解答,所以我就想用 xcodeproj 本身的接口去處理這件事情。
由于 Podfile 本質(zhì)上是 Ruby 腳本,所以這里我通常會使用 Ruby 的 debugger 去操作,通過 Ruby 強大的自省能力,在 debugger 里進行嘗試然后找到我們需要的接口,開始之前我們需要安裝一個 Ruby 的工具,步驟如下:
- 首先是安裝 debugger
gem install pry - 接著在 Podfile 的開頭導(dǎo)入
require 'pry' - 然后在我們想要插入斷點的地方插入
binding.pry語句就可以了
查找能用的接口
我在 post_install 里插入了斷點,接著運行 pod install,就看到斷點生效了:

Ruby 的自省能力非常強大,而且 pry 也基于此做了很多實用的功能,在這里我直接輸入了 installer 回車,就能看到它所有屬性都被遞歸打印出來。
這里面我找了一下之后,發(fā)現(xiàn)一個文檔里沒有記錄的屬性,叫做 pod_target_subprojects,包含了所有 Pods 的項目,似乎可以滿足我們的需求:

接著 Ctrl + d 退出 pry,回到 Podfile 修改即可:
post_install do |installer|
swift_4_0_compatible = [ ... ]
swift_4_2_compatible = [ ... ]
installer.pod_target_subprojects.flat_map { |p| p.targets }.each do |t|
t.build_configurations.each do |c|
c.build_settings['SWIFT_VERSION'] = '4.0' if swift_4_0_compatible.include? t.name
c.build_settings['SWIFT_VERSION'] = '4.2' if swift_4_2_compatible.include? t.name
end
end
end
復(fù)制代碼
最后 pod install 一下,打開 Xcode 查看對應(yīng)的 target 的編譯設(shè)置,確實有效。
這里介紹的 debug 方法在 fastlane 里也適用,非常建議大家在編寫復(fù)雜腳本時先用 debugger 去提前踩坑。