最近在作一款陌生人社交的軟件,市場上這類軟件都是大同小異。爲了能讓產品比競品更具競爭力,作爲開發者,除了完成來自產品經理需求外,咱們能作的還有這些:markdown
我把App啓動速度的優化歸結在交互優化中app
通常狀況下,App的啓動分爲冷啓動和熱啓動異步
app在冷啓動後將程序退到後臺,在app進程還在系統裏的狀況下,用戶重 新啓動進入app的過程,即app從被掛起的狀況下啓動,這個過程作的事情很是少函數
這篇文章主要探討app冷啓動的優化 用戶能感知到的啓動慢,其實都發生在主線程上,而主線程慢的緣由有不少,好比在主線程上執行了大文件讀寫操做、在渲染週期執行了大量計算等。可是,有時候你會發現即便你把首屏顯示以前的這些主線程的耗時問題都解決了,仍是比競品啓動得慢。工具
通常而言,App的啓動時間,指的是從用戶點擊App開始,到用戶看到第一個界面之間的時間,總結來講,App的啓動主要包括三個階段:大數據
main()
函數執行前main()
函數執行後在 main()
函數執行前,系統主要會作下面幾件事:優化
可執行文件
(App的.o
文件的集合)rebase
指針調整和bind
符號綁定objc 運行時
的初始處理,包括objc
相關類的註冊、category
註冊、selector
惟一性檢查等+load()
方法、attribute((constructor))
修飾的函數的調用、建立C++靜態全局變量響應的,在這個階段對於啓動速度優化來講,能夠作的事情包括:動畫
減小動態庫加載
,每一個庫自己都有依賴關係,蘋果官方建議使用更少的動態庫,而且建議在使用動態庫的數量較多時,儘可能將多個動態庫進行合併。數量上,蘋果公司最多能夠支持6個非系統動態庫合併爲1個+load()
方法裏的內容能夠放到首屏渲染完成後再執行,或使用+initialize
方法替換掉。由於,在一個+load()
方法裏,運行運行時方法替換操做會帶來4毫秒的消耗,不要小看這4毫秒,聚沙成塔,執行+load()
方法對啓動速度的影響會愈來愈大C++
全局變量的數量main()函數執行後的階段,指的是從main() 函數執行開始,到 appDelegate的(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
方法裏首屏渲染相關方法執行完成 首頁的業務代碼都是要在這個階段,也就是首屏渲染前執行的,主要包括了:spa
不少時候,咱們會把各類初始化工做都放到這個階段執行(如各種sdk初始化),致使渲染完成置後。更加優化的開發方式,應該是從功能上梳理出哪些是首屏渲染必要的初始化功能,哪些是App啓動必要的初始化功能,而哪些是隻須要在對應功能開始使用時才須要初始化的。梳理完以後,將這些初始化功能分別放到合適的階段進行。線程
首屏渲染完成後的這個階段,主要完成的是,非首屏其它業務服務模塊的初始化、監聽的註冊、配置文件的讀取等。從函數上來看,這個階段指的就是截止到(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
方法做用域內執行首屏渲染以後的全部執行方法。簡單說的話,這個階段就是從渲染完成時,到(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {}
方法做用域結束時結束。
這個階段用戶已經可以看到App的首頁信息了,因此優化的優先級排在最後。可是,那些會卡住主線程的方法仍是須要最優先處理的,否則仍是會影響到用戶後面的交互操做。
明白了App啓動階段須要完成的工做後,咱們就能夠有的放矢的進行啓動速度的優化了。這些優化,包括了功能級別和方法級別的優化
功能級別的啓動優化,就是要從main()
函數執行後這個階段入手
優化的思路是:main()
函數開始執行後到首屏渲染完成前只處理首屏相關的業務,其餘非首屏業務的初始化、監聽註冊、配置文件讀取等都放到首屏渲染完成後去作
通過功能級別的啓動優化,也就是將首屏業務所需的功能滯後之後,當用戶點擊App到看到首屏的時間將會很大程度的縮減,也就達到了優化App啓動速度的目的。
在這以後,咱們須要進一步作的,是堅持首屏渲染完成前主線程上有哪些耗時方法,將不必的耗時方法滯後或者異步執行。一般狀況下,耗時較長的方法主要發生在計算大量數據的狀況下,具體的表現就是加載、編輯、儲存圖片和文件等資源
Time Profile
採用的就是這種方式objc_msgSend
方法進行hook
來掌握全部方法的執行耗時hook
方法的意思是,在原方法開始執行時換成其餘你指定的方法,或者再原有方法執行先後執行你指定的方法,來達到掌握和改變指定方法的目的。
hook
objc_msgSend
這種方式的優勢是很是精確,而缺點是隻能針對Objective-C方法。對於c方法和block,可使用libffi 的ffi_call來達成hook。缺點就是編寫維護相關工具門檻高
綜上,若是對於檢查結果精準度要求高的話,推薦使用hool objc_msgSend方式來檢查啓動方法的執行耗時