前幾天 Cocoapods 1.7.0 正式版釋出了,我最期待的一個功能是 Multiple Pod Projects,昨天順手就給接入了,專案解析和索引效率有了非常明顯的提升,過程中踩了些坑,這次一起把之前 debug 的經驗分享一下。
generate_multiple_pod_projects 選項
之前 Cocoapods 會把每個依賴作為 target 放到 Pods 專案裡,但 xcodeproj 本身的編碼不太能適應這種情況,在引入幾十個 pod 的情況下,專案解析的效率會急劇下降。
以我公司其中一個主專案為例,Pods 專案的大小達到了 5.2 MB(這可都是純文字),在第一次開啟專案,解析專案構建索引時,就能明顯聽到風扇開始狂轉,這個過程會持續好幾分鐘才會結束。
Cocoapods 這次更新引入了一個 generate_multiple_pod_projects 的選項,可以讓每個依賴都作為一個單獨的專案引入,大大增加了解析速度:
開啟的方式很簡單,只要在 Podfile 里加入這一行就可以了:
install! 'cocoapods', generate_multiple_pod_projects: true
複製程式碼
拆分後每個專案的大小都差不多是 40 - 100 kb 左右:
這個選項開啟之後的效果非常顯著,我在 Xcode 裡執行了 clean,之後 indexing 的過程在幾秒鐘裡就結束了,而且風扇也沒有狂轉。
至於為什麼這樣可以提升專案的解析速度,我大概看了一下 xcodeproj 的編碼,所有的 Item 都會按照類別存放到各自的 section 裡,最終在專案的結構樹裡會以引用的形式呈現。
所以檔案引用查詢的範圍是所有 Pod 引用庫的檔案的集合,而每次索引的構建都至少會遍歷一次專案樹,這就會導致索引時間的暴增,除此之外單個龐大的專案解析也不利於多執行緒執行,拆分成多個專案的話就能有效地解決這些問題。
install! 函式只能呼叫一次
需要注意 install!
是個用來配置的函式,由於之前我還開啟了另一個選項,所以接入時是這麼做的:
install! 'cocoapods', generate_multiple_pod_projects: true
install! 'cocoapods', disable_input_output_paths: true
複製程式碼
但是這麼做之後發現不生效,後來才想起來 install!
是一個用來配置的函式,重複呼叫的話,只會以最後一次的呼叫為準。所以應該在一次呼叫裡把它們都傳入進去:
install! 'cocoapods',
disable_input_output_paths: true,
generate_multiple_pod_projects: true
複製程式碼
Swift 版本控制
另一個坑就是在 post_install
時,為了一些版本的相容,需要遍歷所有 target,調整一部分庫的 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
複製程式碼
但是如果開啟了 generate_multiple_pod_projects
的話,由於專案結構的變化,installer.pod_targets
就沒辦法獲得所有 pods 引入的 target 了。
Podfile 裡的程式碼如何 debug
查了 Xcodeproj 和 Cocoapods 的文件之後我都沒有得到很好的解答,所以我就想用 xcodeproj 本身的介面去處理這件事情。
由於 Podfile 本質上是 Ruby 指令碼,所以這裡我通常會使用 Ruby 的 debugger 去操作,通過 Ruby 強大的自省能力,在 debugger 裡進行嘗試然後找到我們需要的介面,開始之前我們需要安裝一個 Ruby 的工具,步驟如下:
- 首先是安裝 debugger
gem install pry
- 接著在 Podfile 的開頭匯入
require 'pry'
- 然後在我們想要插入斷點的地方插入
binding.pry
語句就可以了
查詢能用的介面
我在 post_install 裡插入了斷點,接著執行 pod install
,就看到斷點生效了:
Ruby 的自省能力非常強大,而且 pry 也基於此做了很多實用的功能,在這裡我直接輸入了 installer
回車,就能看到它所有屬性都被遞迴列印出來。
這裡面我找了一下之後,發現一個文件裡沒有記錄的屬性,叫做 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
複製程式碼
最後 pod install
一下,開啟 Xcode 檢視對應的 target 的編譯設定,確實有效。
這裡介紹的 debug 方法在 fastlane 裡也適用,非常建議大家在編寫複雜指令碼時先用 debugger 去提前踩坑。
結語
用慣了 Ruby 的 debug 方式之後,回到 LLDB 感覺體驗差了很多?。
如果覺得文章還不錯的話可以關注一下我的部落格。