app啟動過程分析

前言

文章中的觀點(diǎn)主要通過閱讀蘋果官方文檔和代碼調(diào)試結(jié)果得出,如有偏差或者遺漏的地方,歡迎留言指出。

image

這張圖來自于蘋果的官方文檔,大致描述了app的啟動流程,可以先跳過不看。

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

在Xcode中打開main.m文件,可以看到在main方法中調(diào)用了UIApplicationMain方法,這個(gè)方法承載了app啟動過程中的三個(gè)主要工作:

  1. 根據(jù)方法的第三個(gè)參數(shù),創(chuàng)建UIApplication對象。如果參數(shù)為nil, 則使用UIApplication類。這個(gè)UIApplication對象會以單例的方式存在于app的整個(gè)生命周期,直到app退出;

  2. 根據(jù)第四個(gè)參數(shù),創(chuàng)建UIApplication Delegate對象;

  3. 創(chuàng)建主事件循環(huán)(RunLoop)并啟動。

  4. 加載info.plist, 如plist文件中配置了StoryBoard, 則加載Storyboard中的view.

雖然UIApplicationMain有返回值,但是在整個(gè)程序運(yùn)行期間不會返回,只有在app退出時(shí)才會返回。

實(shí)踐才是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)!

驗(yàn)證一: UIApplication對象和RunLoop對象的創(chuàng)建

創(chuàng)建一個(gè)新的工程,并打開main.m 文件,在main方法體內(nèi)打上斷點(diǎn)
,同時(shí)在AppDelegate.m的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法體內(nèi)也打上斷點(diǎn),重新運(yùn)行一下項(xiàng)目。

項(xiàng)目會停留在main方法中,在debug窗口中打印UIApllication對象和RunLoop對象

po [UIApplication sharedApplication] //返回nil
po [NSRunLoop currentRunLoop].currentMode //返回nil

繼續(xù)執(zhí)行程序,程序會停留在didFinishLaunchingWithOptions方法體內(nèi),在debug窗口中再次打印UIApplication對象和RunLoop對象

po [UIApplication sharedApplication] //返回<UIApplication: 0x7fa6a8400790>
po [NSRunLoop currentRunLoop].currentMode   //返回UIInitializationRunLoopMode

由此可得出,UIApplication對象和RunLoop事件循環(huán)在UIApplicationMain方法中被創(chuàng)建。

驗(yàn)證二:Storyboard的加載

Xcode會在新建的工程中自動創(chuàng)建一個(gè)Main.storyboard文件,并在info.plist配置好。保留驗(yàn)證一里設(shè)置的AppDelegate中設(shè)置的斷點(diǎn),重新運(yùn)行程序,在斷點(diǎn)出打印self.window.rootViewController屬性

 po self.window.rootViewController //<ViewController: 0x7f986ac08090>

由此可見,Main.storyboard在didFinishLaunchingWithOptions回調(diào)方法之前已經(jīng)被自動加載并設(shè)置為window的根對象。

刪除info.plist中的Main storyboard file base name這一項(xiàng),重新運(yùn)行項(xiàng)目,在didFinishLaunchingWithOptions方法中打印self.window

 po self.window // nil

驗(yàn)證三:無論是否有storyboard,didFinishLaunchingWithOptions中回調(diào)中都可以設(shè)置self.window的rootViewController

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    self.window = [[UIWindow alloc] init];
    self.window.rootViewController = [[ViewController alloc] init];
    [self.window makeKeyAndVisible];
    return YES;
}

分別嘗試有storyboard的情況和無storyboard的情況,通過驗(yàn)證可以得出如果有storyboard, UIApplicationMain會先加載storyboard,如果沒有,則需要使用代碼在didFinishLaunchingWithOptions回調(diào)方法里創(chuàng)建self.window對象。

最后梳理一下app啟動過程:

  1. 調(diào)用main()方法;

  2. 調(diào)用并進(jìn)入U(xiǎn)IApplicationMain()方法, 直到程序退出時(shí)方法才會退出。其內(nèi)部的執(zhí)行順序?yàn)椋?/p>

    a. 創(chuàng)建UIApplication對象;

    b. 創(chuàng)建UIApllication的delegate對象;

    c. 加載info.plist文件,如果配置有storyboard文件名,則加載 storyboard;

    d. 開啟一個(gè)主線程的RunLoop,監(jiān)聽事件。

現(xiàn)在,可以回頭看下蘋果的流程圖。

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

相關(guān)閱讀更多精彩內(nèi)容

  • 關(guān)鍵步驟 一個(gè)程序從main函數(shù)開始啟動。代碼如下: int main(int argc, char * argv...
    JzRo閱讀 662評論 0 2
  • //聯(lián)系人:石虎QQ: 1224614774昵稱:嗡嘛呢叭咪哄 一、OC調(diào)用 C++會為靜態(tài)創(chuàng)建的對象生成初始化器...
    石虎132閱讀 2,742評論 0 19
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,622評論 30 472
  • 前言 隨著前端項(xiàng)目的不斷擴(kuò)大,一個(gè)原本簡單的網(wǎng)頁應(yīng)用所引用的js文件可能變得越來越龐大。尤其在近期流行的單頁面應(yīng)用...
    AlienZHOU閱讀 17,299評論 11 26
  • 泥人 綿延的雨季已然來臨 你要記住風(fēng)的模樣 你要記住雨的模樣 你要記住你自己的模樣 因?yàn)槟闶且粋€(gè)泥人 一個(gè)泥人最后...
    等一場煙雨迷閱讀 202評論 1 3

友情鏈接更多精彩內(nèi)容