iOS性能(二) 啟動時間優(yōu)化

冷啟動 與 熱啟動
  • 熱啟動:如果你剛剛啟動過App,這時候App的啟動所需要的數(shù)據仍然在緩存中,再次啟動的時候稱為熱啟動。通常情況下熱啟動能幫助提升啟動速度,但有時也可能會出現(xiàn)app卡死手動退出進程后重新打開仍然是卡死狀態(tài)。
  • 冷啟動:如果是比較長時間沒有啟動過app或者設備剛剛重啟,這種情況下啟動App,就被稱為冷啟動。
查看啟動時間
  • 最佳速度:400ms,因為不添加任何同步任務從圖標被點擊到顯示Launch Screen,然后Launch Screen消失這段時間就是400ms。如果app啟動時間接近這個數(shù)值,那證明app的啟動任務已經優(yōu)化到最佳。
  • 最慢速度:不可以大于20s,否則會被系統(tǒng)殺掉。

配置Xcode環(huán)境變量在日志中打印啟動時間:
打開工程 -> Edit Scheme -> Run -> Environment Variables
根據需要添加DYLD_PRINT_STATISTICSDYLD_PRINT_STATISTICS_DETAILS環(huán)境變量,1表示Yes,開啟這個功能。

屏幕快照 2019-05-27 下午3.13.41.png

Total pre-main time: 433.19 milliseconds (100.0%)
         dylib loading time: 341.79 milliseconds (78.8%)
        rebase/binding time:  14.18 milliseconds (3.2%)
            ObjC setup time:  35.27 milliseconds (8.1%)
           initializer time:  41.79 milliseconds (9.6%)
           slowest intializers :
             libSystem.B.dylib :   3.40 milliseconds (0.7%)
    libMainThreadChecker.dylib :  19.68 milliseconds (4.5%)
  libViewDebuggerSupport.dylib :   8.75 milliseconds (2.0%)
優(yōu)化啟動

以main函數(shù)作為分水嶺,啟動時間其實包括了兩部分:main函數(shù)之前和main函數(shù)到第一個界面的viewDidAppear:。
所以,優(yōu)化也是從兩個方面進行的,優(yōu)化效果主要來自于后者,因為絕大多數(shù)App的瓶頸在自己的代碼里。而對于pre-main的優(yōu)化能做的無非是減少不必要的動態(tài)庫引用、多個庫合并成一個,從上面的打印數(shù)據也可以看出,主要耗時是在dylib loading,消耗78.8%的時間。

Main函數(shù)之后

從main函數(shù)開始執(zhí)行,到第一個界面顯示,期間一般做以下任務:

  • 執(zhí)行AppDelegate的代理方法,主要是didFinishLaunchingWithOptions
  • 初始化Window,初始化基礎的ViewController結構(一般是UINavigationController+UITabViewController+多個UIViewController)
  • 獲取數(shù)據(Local DB/Network),展示給用戶。

優(yōu)化:

  1. 延遲初始化和加載不必要的UIViewController和View。

比方說UITabViewController有四個Item,在啟動的時候盡量只初始化首頁的頁面,其它Item頁面先用空VC占位。而且首頁的內容中不必要的內容也可以先不初始化,做成懶加載形式,在用戶確實需要查看和使用時再初始化。

  1. 對于確實需要啟動時使用但又比較耗時的事物放倒后臺處理,如果涉及到UI則在處理完成后把刷新任務放回主線程。

日志功能,日志往往涉及到DB操作;
文件讀取,比如讀取本地存儲的省份城市區(qū)縣文件和圖片處理;
大量的計算,比如圖片處理、比較大的json數(shù)據轉Model;

  1. 能延遲初始化的盡量延遲初始化

三方SDK初始化,比如Crash統(tǒng)計、 像分享之類的,可以等到第一次調用再出初始化。

Main函數(shù)之前

Main函數(shù)之前是iOS系統(tǒng)的工作,所以這部分的優(yōu)化往往更具有通用性。
Pre-Main包含以下工作:

- dylib loading time: 341.79 milliseconds (78.8%)
- rebase/binding time:  14.18 milliseconds (3.2%)
- ObjC setup time:  35.27 milliseconds (8.1%)
- initializer time:  41.79 milliseconds (9.6%)
- slowest intializers :
- libSystem.B.dylib :   3.40 milliseconds (0.7%)
- libMainThreadChecker.dylib :  19.68 milliseconds (4.5%)
- libViewDebuggerSupport.dylib :   8.75 milliseconds (2.0%)

優(yōu)化:

  1. loading dylib:啟動的第一步是加載動態(tài)庫,加載系統(tǒng)的動態(tài)庫使很快的,因為可以緩存,而加載內嵌的動態(tài)庫速度較慢。所以,提高這一步的效率的關鍵是:減少動態(tài)庫的數(shù)量。
  • 合并動態(tài)庫,比如公司內部由私有Pod建立了如下動態(tài)庫:XXTableView, XXHUD, XXLabel,強烈建議合并成一個XXUIKit來提高加載速度。
  1. rebase/binding & ObjC Runtime setup:Rebase和Binding都是為了解決指針引用的問題。對于Objective C開發(fā)來說,主要的時間消耗在Class/Method的符號加載上,所以常見的優(yōu)化方案是:
  • 減少__DATA段中的指針數(shù)量。
  • 合并Category和功能類似的類。比如:UIView+Frame,UIView+AutoLayout…合并為一個
  • 刪除無用的方法和類。
  • 多用Swift Structs,因為Swfit Structs是靜態(tài)分發(fā)的。可以參考Swift進階之內存模型和方法調度
  1. Initializers
  • 用initialize替代load。不少同學喜歡用method-swizzling來實現(xiàn)AOP去做日志統(tǒng)計等內容,強烈建議改為在initialize進行初始化。
    load在程序啟動的時候就會調用,而且必須阻塞等著所有類的load方法都執(zhí)行完;initialize在類首次使用的時候調用。

  • 減少__atribute__((constructor))的使用(__attribute__((constructor))用是在main函數(shù)之前,執(zhí)行一個函數(shù),便于我們做一些準備工作)。


參考資料

深入理解iOS App的啟動過程

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 背景 一個項目做的時間長了,啟動流程往往容易雜亂,庫也用的越來越多,APP的啟動時間也會慢慢變長。本次將針對iOS...
    醬油瓶2閱讀 3,647評論 0 12
  • 前言 最近和公司iOS小組伙伴討論準備對各自手上的產品做一次優(yōu)化,確實對比很多產品來看,(支付寶,淘寶,幾乎1~2...
    Cingjin閱讀 1,874評論 0 7
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,629評論 1 32
  • 每個童話里都有美麗善良、集千萬寵愛于一身或歷盡苦難最后過上幸福生活的公主和一個丑惡無比、對公主百般虐待的女巫。 每...
    女巫的夢想閱讀 785評論 0 2
  • 我高興的、傷悲的、興奮的、苦悶的、心動的、絕望的...要死了...但...那么的波濤洶涌,卻也只能如此了。 188...
    緹米米閱讀 563評論 0 0

友情鏈接更多精彩內容