iOS APP啟動函數(shù)調(diào)用順序~詳解

//聯(lián)系人:石虎QQ: 1224614774昵稱:嗡嘛呢叭咪哄

一、OC調(diào)用

C++會為靜態(tài)創(chuàng)建的對象生成初始化器,與靜態(tài)語言不同,OC基于Runtime機制可以用類的名字來實例化一個類的對象。Runtime維護了一張映射類名與類的全局表,當加載一個dylib時,其定義的所有的類都需要被注冊到這個全局表中。ObjC在加載時可以通過fix-up在動態(tài)類中改變實例變量的偏移量,利用這個技術(shù)可以在不改變dylib的情況下添加另一個dylib中類的方法,而非常見的通過定義類別(Category)的方式改變一個類的方法。

主執(zhí)行文件和相關(guān)的dylib的依賴關(guān)系構(gòu)成了一張巨大的有向圖,執(zhí)行初始化器先加載葉子節(jié)點,然后逐步向上加載中間節(jié)點,直至最后加載根節(jié)點。這種加載順序確保了安全性,加載某個dylib前,其所依賴的其余dylib文件肯定已經(jīng)被預(yù)先加載。最后dyld會調(diào)用main()函數(shù)。main()會調(diào)用UIApplicationMain(),程序啟動。

二、程序啟動邏輯

使用Xcode打開一個項目,很容易會發(fā)現(xiàn)一個文件--main.m文件,此處就是應(yīng)用的入口了。程序啟動時,先執(zhí)行main函數(shù),main函數(shù)是ios程序的入口點,內(nèi)部會調(diào)用UIApplicationMain函數(shù),UIApplicationMain里會創(chuàng)建一個UIApplication對象,然后創(chuàng)建UIApplication的delegate對象—–(您的)AppDelegate,開啟一個消息循環(huán)(main runloop),每當監(jiān)聽到對應(yīng)的系統(tǒng)事件時,就會通知AppDelegate。

int?main(int?argc,char?*?argv[]){

@autoreleasepool?{

return?UIApplicationMain(argc,argv,nil,NSStringFromClass([AppDelegate?class]));

}

}

UIApplication對象是應(yīng)用程序的象征,每一個應(yīng)用都有自己的UIApplication對象,而且是單例的。通過[UIApplication sharedApplication]可以獲得這個單例對象,一個iOS程序啟動后創(chuàng)建的第一個對象就是UIApplication對象,利用UIApplication對象,能進行一些應(yīng)用級別的操作。

三、UIApplicationMain函數(shù)實現(xiàn)如下:

int?UIApplicationMain{

int?argc,

char?*argv[],

NSString?*principalClassName,

NSString?*?delegateClassName

}

第一個參數(shù)表示參數(shù)的個數(shù),第二個參數(shù)表示裝載函數(shù)的數(shù)組,第三個參數(shù),是UIApplication類名或其子類名,若是nil,則默認使用UIApplication類名。第四個參數(shù)是協(xié)議UIApplicationDelegate的實例化對象名,這個對象就是UIApplication對象監(jiān)聽到系統(tǒng)變化的時候通知其執(zhí)行的相應(yīng)方法。

啟動完畢會調(diào)用didFinishLaunching方法,并在這個方法中創(chuàng)建UIWindow,設(shè)置AppDelegate的window屬性,并設(shè)置UIWindow的根控制器。如果有storyboard,會根據(jù)info.plist中找到應(yīng)用程序的入口storyboard并加載箭頭所指的控制器,顯示窗口。storyboard和xib最大的不同在于storyboard是基于試圖控制器的,而非視圖或窗口。展示之前會將添加rootViewController的view到UIWindow上面(在這一步才會創(chuàng)建控制器的view)

1[window?addSubview:?window.rootViewControler.view];

每個應(yīng)用程序至少有一個UIWindow,這window負責管理和協(xié)調(diào)應(yīng)用程序的屏幕顯示,rootViewController的view將會作為UIWindow的首視圖。

未使用storyboard的啟動

四、程序啟動的完整過程如下:

1.main函數(shù)

2.UIApplicationMain

創(chuàng)建UIApplication對象

創(chuàng)建UIApplication的delegate對象

delegate對象開始處理(監(jiān)聽)系統(tǒng)事件(沒有storyboard)

程序啟動完畢的時候,就會調(diào)用代理的application:didFinishLaunchingWithOptions:方法

在application:didFinishLaunchingWithOptions:中創(chuàng)建UIWindow

創(chuàng)建和設(shè)置UIWindow的rootViewController

顯示窗口

3.根據(jù)Info.plist獲得最主要storyboard的文件名,加載最主要的storyboard(有storyboard)

創(chuàng)建UIWindow

創(chuàng)建和設(shè)置UIWindow的rootViewController

顯示窗口

五、AppDelegate的代理方法

//app啟動完畢后就會調(diào)用

-(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary?*)launchOptions

{

}

//app程序失去焦點就會調(diào)用

-(void)applicationWillResignActive:(UIApplication?*)application

{

}

//app進入后臺的時候調(diào)用,一般在這里保存應(yīng)用的數(shù)據(jù)(游戲數(shù)據(jù),比如暫停游戲)

-(void)applicationDidEnterBackground:(UIApplication?*)application

{

}

//app程序程序從后臺回到前臺就會調(diào)用

-(void)applicationWillEnterForeground:(UIApplication?*)application

{

}

//app程序獲取焦點就會調(diào)用

-(void)applicationDidBecomeActive:(UIApplication?*)application

{

}

//內(nèi)存警告,可能要終止程序,清除不需要再使用的內(nèi)存

-(void)applicationDidReceiveMemoryWarning:(UIApplication?*)application

{

}

//程序即將退出調(diào)用

-(void)applicationWillTerminate:(UIApplication?*)application

{

}

AppDelegate加載順序

1.application:didFinishLaunchingWithOptions:

2.applicationDidBecomeActive:

ViewController中的加載順序

1.loadView

2.viewDidLoad

3.viewWillAppear

4.viewWillLayoutSubviews

5.viewDidLayoutSubviews

6.viewDidAppear

View中的加載順序

1.initWithCoder(如果沒有storyboard就會調(diào)用initWithFrame,這里兩種方法視為一種)

2.awakeFromNib

3.layoutSubviews

4.drawRect

一些方法的使用時機

1+(void)load;

應(yīng)用程序啟動就會調(diào)用的方法,在這個方法里寫的代碼最先調(diào)用。

1+(void)initialize;

用到本類時才調(diào)用,這個方法里一般設(shè)置導航控制器的主題等,如果在后面的方法設(shè)置導航欄主題就太遲了!

1-(BOOL)application:(UIApplication?*)application?didFinishLaunchingWithOptions:(NSDictionary*)launchOptions;

這個方法里面會創(chuàng)建UIWindow,設(shè)置根控制器并展現(xiàn),比如某些應(yīng)用程序要加載授權(quán)頁面也是在這加,也可以設(shè)置觀察者,監(jiān)聽到通知切換根控制器等。

1-(void)awakeFromNib;

在使用IB的時候才會涉及到此方法的使用,當.nib文件被加載的時候,會發(fā)送一個awakeFromNib的消息到.nib文件中的每個對象,每個對象都可以定義自己的awakeFromNib函數(shù)來響應(yīng)這個消息,執(zhí)行一些必要的操作。在這個方法里設(shè)置view的背景等一系列普通操作。

1-(void)loadView;

創(chuàng)建視圖的層次結(jié)構(gòu),在沒有創(chuàng)建控制器的view的情況下不能直接寫self.view因為self.view的底層是:

if(_view?==?nil){

_view?=[self?loadView]

}

這么寫會直接造成死循環(huán)。

如果重寫這個loadView方法里面什么都不寫,會顯示黑屏。

1-(void)viewWillLayoutSubviews;

視圖將要布局子視圖,蘋果建議的設(shè)置界面布局屬性的方法,這個方法和viewWillAppear里,系統(tǒng)的底層都是沒有寫任何代碼的,也就是說這里面不寫super也是可以的。

1-(void)layoutSubviews;

在這個方法里一般設(shè)置子控件的frame。

1-(void)drawRect:(CGRect)rect;

UI控件都是畫上去的,在這一步就是把所有的東西畫上去。drawRect方法只能在加載時調(diào)用一次,如果后面還需要調(diào)用,比如下載進度的圓弧,需要一直刷幀,就要使用setNeedsDisplay來定時多次調(diào)用本方法。

1-(void)applicationDidBecomeActive:(UIApplication?*)application;

這是AppDelegate的應(yīng)用程序獲取焦點方法,真正到了這里,才是所有東西全部加載完畢。

六、啟動分析

應(yīng)用啟動時,會播放一個啟動動畫。iPhone上是400ms,iPad上是500ms。如果應(yīng)用啟動過慢,用戶就會放棄使用,甚至永遠都不再回來。為了防止一個應(yīng)用占用過多的系統(tǒng)資源,開發(fā)iOS的蘋果工程師門設(shè)計了一個“看門狗”的機制。在不同的場景下,“看門狗”會監(jiān)測應(yīng)用的性能。如果超出了該場景所規(guī)定的運行間,“看門狗”就會強制終結(jié)這個應(yīng)用的進程。

iOS App啟動時會鏈接并加載Framework和static lib,執(zhí)行UIKit初始化,然后進入應(yīng)用程序回調(diào),執(zhí)行Core Animation transaction等。每個Framework都會增加啟動時間和占用的內(nèi)存,不要鏈接不必要的Framework,必要的Framework不要標記為Optional。避免創(chuàng)建全局的C++對象。

初始化UIKit時字體、狀態(tài)欄、user defaults、Main.storyboard會被初始化。User defaults本質(zhì)上是一個plist文件,保存的數(shù)據(jù)是同時被反序列化的,不要在user defaults里面保存圖片等大數(shù)據(jù)。

對于OC來說應(yīng)盡量減少Class,selector和category這些元數(shù)據(jù)的數(shù)量。編碼原則和設(shè)計模式之類的理論會鼓勵大家多寫精致短小的類和方法,并將每部分方法獨立出一個類別,但這會增加啟動時間。在調(diào)用的地方使用初始化器,不要使用\\atribute((constructor))將方法顯式標記為初始化器,而是讓初始化方法調(diào)用時才執(zhí)行。比如使用dispatch_once(),pthread_once()或std::once()。也就是在第一次使用時才初始化,推遲了一部分工作耗時。

建立網(wǎng)絡(luò)連接前需要做域名解析,如果網(wǎng)關(guān)出現(xiàn)問題,dns解析不正常時,dns的超時時間是應(yīng)用控制不了的。在程序設(shè)計時要考慮這些問題,如果程序啟動時有網(wǎng)絡(luò)連接,應(yīng)盡快的結(jié)束啟動過程,網(wǎng)絡(luò)訪問通過線程解決,而不阻塞主線程的運行。

謝謝!!!

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

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

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