iOS App啓動優化(一)—— 瞭解App的啓動流程

級別:★☆☆☆☆
標籤:「iOS」「啓動流程」「啓動優化」
做者: 647
審校: QiShare團隊php


前言:
最近,小編在看戴銘老師的技術分享,感受收穫不少。基於最近的學習,小編總結了一些App啓動優化上的知識點,並計劃落地一系列App啓動優化的文章。

目錄以下:
iOS App啓動優化(一)—— 瞭解App的啓動流程
iOS App啓動優化(二)—— 使用「Time Profiler」工具監控App的啓動耗時
iOS App啓動優化(三)—— 本身作一個工具監控App的啓動耗時html


本篇將介紹App的兩種啓動方式:「冷/熱啓動」、App完整啓動流程以及「優化思路」。git

1、「冷啓動」與「熱啓動」

首先,咱們先來區分兩個啓動的概念。github

  • 冷啓動:
    App點擊啓動前,此時App的進程還不在系統裏。
    須要系統新建立一個進程分配給App。(這是一次完整的App啓動過程)微信

  • 熱啓動:
    App在冷啓動後用戶將App退回後臺,此時App的進程還在系統裏。
    用戶從新返回App的過程。(熱啓動作的事較少)網絡

主要區別:app

名稱 區別
冷啓動 啓動時,App的進程不在系統裏,須要開啓新進程。
熱啓動 啓動時,App的進程還在系統裏,不須要開啓新進程。

2、App的完整啓動流程(冷啓動流程)

主要分爲三個階段:異步

  1. main() 函數執行前(pre-main階段)
  2. main() 函數執行後(從main函數執行,到設置self.window.rootViewController執行完成)
  3. 首屏渲染完成後(從self.window.rootViewController執行完成到didFinishLaunchWithOptions方法做用域結束)

(1)main函數執行前,系統會作的事:
  • 加載可執行文件。(App裏的全部.o文件)函數

  • 加載動態連接庫,進行rebase指針調整和bind符號綁定。工具

  • ObjCruntime初始化。 包括: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++靜態全局變量。


(2)main函數執行後:

main函數執行後的階段,指的是:從 main 函數執行開始,到 appDelegatedidFinishLaunchingWithOptions方法裏首屏渲染相關方法執行完成。 即,從main函數執行到設置self.window.rootViewController執行完成的階段。

  • 首屏初始化所需配置文件的讀寫操做;

  • 首屏列表大數據的讀取;

  • 首屏渲染的大量計算;

main函數執行後


(3)首屏渲染完成後:

首屏渲染完成後的階段,指的是:didFinishLaunchingWithOptions方法做用域 內執行首屏渲染後的全部方法執行。 即從設置self.window.rootViewControllerdidFinishLaunchWithOptions方法做用域結束。

這個階段,首屏已經渲染完成。

須要作的事:

  • 初始化一些首屏展現不須要的功能。

  • 優化主線程,先處理會卡住主線程的方法,不能影響到用戶的後續操做。


3、具體優化思路

用戶能感知到的啓動時長主要是在 「main函數執行前」 、**「main函數執行後到首屏渲染完成」**的階段。

main函數執行前,優化思路以下:

(1)減小使用 +load() 方法
  • 方案一:若是可能的話,將+load中的內容,放到渲染完成後作。

  • 方案二:使用+initialize()的方法代替+load(),注意把邏輯移動到+initialize()時,要注意避免+initialize()的重複調用問題,可使用dispatch_once()讓邏輯只執行一次。

小知識點:+load()+initialize()二者的區別?
+load()方法會在main()函數調用前就調用,而+initialize()是在類第一次使用時纔會調用。
+load方法的調用優先級: 父類 > 子類 > 分類,而且不會被覆蓋,均會調用。
+load方法是在main() 函數以前調用,全部的類文件都會加載,包括分類也會加載。 +initialize方法的調用優先級:分類 > 子類,父類 > 子類。(父類的分類重寫了+initialize方法會覆蓋父類的+initialize方法)

(2)合併多個動態庫

蘋果公司建議使用更少的動態庫,而且建議在使用動態庫的數量較多時,儘可能將多個動態庫進行合併。數量上,蘋果公司最多能夠支持6個非系統動態庫合併爲一個。

(3)優化類、方法、全局變量

減小加載啓動後不會去使用的類或方法;少用C++全局變量;

main函數執行後,優化方案以下:

(4)優化首屏渲染前的功能初始化

main函數執行後到首屏渲染完成前,只處理首屏渲染相關業務。 首屏渲染外的其餘功能放到首屏渲染完成後去初始化。

(5)優化主線程耗時操做,防止屏幕卡頓。

首先檢查首屏渲染前,主線程上的耗時操做。將耗時操做滯後或異步處理。 一般的耗時操做有:網絡加載、編輯、存儲圖片和文件等資源。 針對耗時操做作相對應的優化便可。


小編微信:可加並拉入《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(一)
奇舞週刊

相關文章
相關標籤/搜索