本文要是要針對啓動優化相關概念和最佳實踐的介紹。算法
什麼是啓動
首先來看一下啓動類型都有哪幾種,以及每種啓動類型的特色。緩存
啓動類型
共有三種啓動類型,分別爲:冷啓動、熱啓動和從新啓動,下面爲它們的特色。markdown
- 冷啓動
- 重啓以後。
- APP 未在 iPhone 的內存中。
- APP 線程不存在。
- 熱啓動
- 最近被終止的。
- APP 部分在內存中。
- APP 線程不存在。
- 從新啓動
- APP 被暫停(好比按下 home 鍵)。
- 整個 APP 都在內存中。
- APP 線程存在。
介紹完啓動類型,下面來看一下啓動共分爲幾個階段以及每一個階段的應該避免的作法。數據結構
啓動的六大階段
六大階段分別爲:系統接口初始化(System Interface)、Runtime 初始化、UIKit 初始化、Application 初始化、初始化第一幀、擴展(Extended)。app
先看下每一個階段都具體作了哪些事情。異步
- System Interface:初始化底層的系統接口、系統部分的工做花費固定的時間,也就是說該階段的系統部分是不用咱們操心的。
- Runtime Init:初始化語言的運行時環境、調用全部類的靜態 load 方法。
- UIKit Init:實例化 UIApplication 和 UIApplicationDelegate、開始事件處理和系統集成。
- Application Init:調用 UIApplicationDelegate/UISceneDelegate 生命週期的回調,好比:
application:willFinishLaunchingWithOptions:
。
- Initial Frame Render:建立、執行佈局,並繪製視圖;提交渲染第一幀。
loadView/viewDidLoad/layoutSubviews
- Extended:該階段爲顯示第一幀後的特定時間,該階段會異步加載數據,你的 APP 在當前階段應該是可交互、可響應的。
下面看下每一個階段應該避免的作法。數據結構和算法
- System Interface
- 避免鏈接沒用的 framework。
- 避免在啓動階加載動態庫。
- 硬連接全部的依賴。
- Runtime Init
- 減小 +load 方法的調用。
- 使用 +initialize 去懶加載靜態初始化。
- 暴露 framework 中的初始化 API。
- UIKit Init
- 減小 UIApplication 子類的工做。
- 減小 UIApplicationDelegate 初始化的工做。
- Application Init
- 延後 UIApplicationDelegate 生命週期中不相關的工做。
- 兩個 scenes 之間共享資源。
- Initial Frame Render
- Extended
介紹完啓動類型和啓動階段,接下來看一下如何正確的測量。佈局
正確的測量啓動
在進行啓動時間測量時,應對屢次測量環境保持乾淨一致的測量環境,這樣測量的結果纔會有說服力。post
能夠經過下面的方法來保持環境的一致性:性能
- 重啓手機,並放置2-3min。
- 啓動飛行模式或者 mock 環境。
- 不使用 iCloud 帳戶,或者使用一致的 iCloud 帳戶。
- 使用 App 的 release 模式。
- 測量熱啓動。
在測量過程當中咱們應對新舊設備都進行測試。
啓動時間能夠經過 XCTest 來進行測試。
如何優化啓動時間
主要經過下面的三大塊來優化。
減小工做量
- 延後與第一幀不相關的工做。好比
application:willFinishLaunchingWithOptions:
裏不重要的接口調用。
- 移除阻塞主線層的代碼。耗時的操做確定要放在子線程異步處理。
- 減小內存的使用。
指定正確的優先級
這一塊主要針對正確的使用 GCD。
- 對於 task 使用正確的 Qos。
- 利用 scheduler 來優化啓動。
- 使用正確的原語優先級。
優化代碼
- 簡化已有代碼。
- 使用正確的數據結構和算法。
- 緩存一切可緩存的。
總結
- 優化啓動時間很重要,咱們要讓它成爲平常開發的一部分。
- 刪除一切不須要的代碼合資源。
- 正確的使用 GCD、數據結構和算法。
- 重構簡化現有代碼。
- 儘量多的緩存。