前言:
最近,小編在看戴銘老師的技術分享,感受收穫不少。基於最近的學習,小編總結了一些App啓動優化上的知識點,並計劃落地一系列App啓動優化的文章。
目錄以下:
iOS App啓動優化(一)—— 瞭解App的啓動流程
iOS App啓動優化(二)—— 使用「Time Profiler」工具監控App的啓動耗時
iOS App啓動優化(三)—— 本身作一個工具監控App的啓動耗時html
本篇將介紹App的兩種啓動方式:「冷/熱啓動」、App完整啓動流程以及「優化思路」。git
首先,咱們先來區分兩個啓動的概念。github
冷啓動:
App
點擊啓動前,此時App
的進程還不在系統裏。
須要系統新建立一個進程分配給App
。(這是一次完整的App
啓動過程)微信
熱啓動:
App
在冷啓動後用戶將App
退回後臺,此時App
的進程還在系統裏。
用戶從新返回App
的過程。(熱啓動作的事較少)網絡
主要區別:app
名稱 | 區別 |
---|---|
冷啓動 | 啓動時,App的進程不在系統裏,須要開啓新進程。 |
熱啓動 | 啓動時,App的進程還在系統裏,不須要開啓新進程。 |
主要分爲三個階段:異步
main()
函數執行前(pre-main階段)main()
函數執行後(從main
函數執行,到設置self.window.rootViewController
執行完成)self.window.rootViewController
執行完成到didFinishLaunchWithOptions
方法做用域結束)加載可執行文件。(App
裏的全部.o
文件)函數
加載動態連接庫,進行rebase
指針調整和bind
符號綁定。工具
ObjC
的runtime
初始化。 包括:ObjC
相關Class
的註冊、category
註冊、selector
惟一性檢查等。
初始化。 包括:執行+load()
方法、用attribute((constructor))
修飾的函數的調用、建立C++
靜態全局變量等。
簡單來講,
App啓動後,首先,系統內核(Kernel)建立一個進程。
其次,加載可執行文件。(可執行文件是指Mach-O格式的文件,也就是App中全部.o文件的集合體)這時,能獲取到dyld(dyld是蘋果的動態連接器)的路徑。
而後,加載dyld,主要分爲4步:
1 . load dylibs:這一階段dyld會分析應用依賴的dylib
,找到其mach-o
文件,打開和讀取這些文件並驗證其有效性,接着會找到代碼簽名註冊到內核,最後對dylib
的每個segment
調用mmap()。
2 . rebase/bind:進行rebase
指針調整和bind
符號綁定。
3 . ObjC setup:runtime運行時初始化。包括ObjC
相關Class
的註冊、category
註冊、selector
惟一性檢查等。
4 . Initializers:調用每一個ObjC
類與分類的+load
方法,調用attribute((constructor))
修飾的函數、建立C++
靜態全局變量。
main函數執行後的階段,指的是:從 main
函數執行開始,到 appDelegate
的 didFinishLaunchingWithOptions
方法裏首屏渲染相關方法執行完成。 即,從main
函數執行到設置self.window.rootViewController
執行完成的階段。
首屏初始化所需配置文件的讀寫操做;
首屏列表大數據的讀取;
首屏渲染的大量計算;
首屏渲染完成後的階段,指的是:didFinishLaunchingWithOptions
方法做用域 內執行首屏渲染後的全部方法執行。 即從設置self.window.rootViewController
到didFinishLaunchWithOptions
方法做用域結束。
這個階段,首屏已經渲染完成。
須要作的事:
初始化一些首屏展現不須要的功能。
優化主線程,先處理會卡住主線程的方法,不能影響到用戶的後續操做。
用戶能感知到的啓動時長主要是在 「main函數執行前」 、**「main函數執行後到首屏渲染完成」**的階段。
main函數執行前,優化思路以下:
+load()
方法方案一:若是可能的話,將+load
中的內容,放到渲染完成後作。
方案二:使用+initialize()
的方法代替+load()
,注意把邏輯移動到+initialize()
時,要注意避免+initialize()
的重複調用問題,可使用dispatch_once()
讓邏輯只執行一次。
小知識點:
+load()
與+initialize()
二者的區別?
+load()
方法會在main()函數調用前就調用,而+initialize()
是在類第一次使用時纔會調用。
+load
方法的調用優先級: 父類 > 子類 > 分類,而且不會被覆蓋,均會調用。
+load
方法是在main() 函數以前調用,全部的類文件都會加載,包括分類也會加載。+initialize
方法的調用優先級:分類 > 子類,父類 > 子類。(父類的分類重寫了+initialize
方法會覆蓋父類的+initialize
方法)
蘋果公司建議使用更少的動態庫,而且建議在使用動態庫的數量較多時,儘可能將多個動態庫進行合併。數量上,蘋果公司最多能夠支持6
個非系統動態庫合併爲一個。
減小加載啓動後不會去使用的類或方法;少用C++全局變量;
main函數執行後,優化方案以下:
main函數執行後到首屏渲染完成前,只處理首屏渲染相關業務。 首屏渲染外的其餘功能放到首屏渲染完成後去初始化。
首先檢查首屏渲染前,主線程上的耗時操做。將耗時操做滯後或異步處理。 一般的耗時操做有:網絡加載、編輯、存儲圖片和文件等資源。 針對耗時操做作相對應的優化便可。
小編微信:可加並拉入《QiShare技術交流羣》。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
iOS WKWebView的基本使用
Swift 5.1 (4) - 集合類型
iOS 解析一個自定義協議
iOS13 DarkMode適配(二)
iOS13 DarkMode適配(一)
2019蘋果秋季新品發佈會速覽
申請蘋果開發者帳號的流程
Sign In With Apple(一)
奇舞週刊