iOS程序啟動原理

一個程序從main函數(shù)開始啟動楼咳。

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

可以看到main函數(shù)會調用UIApplicationMain函數(shù)但指,它的四個參數(shù)的意思是:

argc: 代表程序在進入main函數(shù)時的參數(shù)的個數(shù)。默認為1。
argv: 代表包含的各個參數(shù)。默認為程序的名字式廷。
principalClassName: UIApplication或者它的子類的名字, 如果傳入的是nil, 則表示UIApplication的名字, 即@"UIApplication"。
delegateClassName: UIApplication的代理的名字芭挽。

在UIApplicationMain函數(shù)中滑废,根據(jù)傳入的UIApplication名稱和它的代理的名稱,會主要做下面的事情:

  • 根據(jù)傳入的名稱創(chuàng)建UIApplication對象袜爪。
  • 根據(jù)傳入的代理名稱創(chuàng)建UIApplication代理對象策严。
  • 開啟事件循環(huán)(如果不進行循環(huán),那么在main函數(shù)結束后程序就結束了饿敲。要保證程序創(chuàng)建后可以一直存在)。
  • 解析Info.plist文件逛绵。
    • 會在Info.plist文件里查找Main storyboard file base name這個Key對應的Value是否有值怀各。如果有值,則表示之后會通過Storyboard加載控制器术浪,AppDelegate會接收到didFinishLaunchingWithOptions消息(程序啟動完成的時候)瓢对,此時Storyboard會進行一系列的加載操作(后面會具體說);如果沒有值胰苏,則不會通過Storyboard加載控制器硕蛹,接著AppDelegate會接收到didFinishLaunchingWithOptions消息(程序啟動完成的時候),在這個時候需要我們通過代碼的方式加載控制器硕并。
    • 注意Info.plist中Main storyboard file base name這個Key并不是真正的Key法焰,而是蘋果為了增強可讀性才這樣寫的,真正的Key為UIMainStoryboardFile(可以通過Info.plist文件的源代碼查看)倔毙。
    • 這就是在想要用代碼方式創(chuàng)建控制器而不是Storyboard創(chuàng)建控制器的時候為什么先要將Main Interface設置為空白埃仪,這樣在解析Info.plist文件的時候才會知道不通過Storyboard創(chuàng)建控制器。
    • 由此可以知道陕赃,解析Info.plist文件這一操作主要是看我們用的是Storyboard方式加載還是代碼的方式加載卵蛉。默認Main storyboard file base nameMain颁股,也就是通過Storyboard方式加載控制器。

現(xiàn)在具體分析一下傻丝,通過Storyboard方式加載控制器和代碼方式加載控制器甘有。

通過Storyboard

通過Storyboard,主要做了下面的事情(這些事情不需要我們做葡缰,是系統(tǒng)自動完成的亏掀,在程序啟動完成的時候):

  • 創(chuàng)建窗口。

    創(chuàng)建一個UIWindow的實例用來顯示界面运准。

  • 設置窗口的根控制器幌氮。

    • 根據(jù)Storyboard的設置,創(chuàng)建一個控制器胁澳。
    • 并且設置這個控制器為之前創(chuàng)建的window的根控制器该互。
  • 顯示窗口。(相當于后面提到的makeKeyAndVisible)

    設置self.window可見并且設置UIApplication的keyWindow韭畸。

    在這一步中將根控制器的view添加到window上宇智。

通過代碼方式

通過代碼的方式,需要我們在didFinishLaunchingWithOptions方法中進行加載控制器的相關操作胰丁。

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

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    UIViewController *viewController = [[UIViewController alloc] init];
    self.window.rootViewController = viewController;
    // 此時根控制器的view還沒有加到self.window上
    [self.window makeKeyAndVisible];
    // 此時根控制器的view加到self.window上
    return YES;
}

其實這里所做和系統(tǒng)所做是一樣的随橘。(相當于系統(tǒng)的做法)

  • 首先創(chuàng)建窗口,得到一個正確的UIWindow實例對象用來顯示界面锦庸。(self.window是系統(tǒng)自帶的屬性)

  • 接著設置窗口的根控制器机蔗。

    • 不再根據(jù)Storyboard中的設置加載,此時需要我們自己創(chuàng)建控制器甘萧。
    • 設置這個控制器為self.window的根控制器萝嘁。
    • 注意這個時候根控制器的view還沒有加到self.window上,當窗口要顯示的時候,才會把窗口的根控制器的view添加到窗口扬卷。(可以輸出self.window.subViews來驗證)
  • 顯示窗口牙言。

    [self.window makeKeyAndVisible]實際上做了下面的事:

    首先,將self.window設置為UIApplication的keyWindow怪得,這么做是方便我們以后查看UIApplication的主窗口是哪一個咱枉。

    接著,讓self.window可見徒恋,相當于執(zhí)行的代碼是:

    self.window.hidden = NO;
    

    這么做的原因是self.window默認hidden = YES蚕断,所以需要讓其顯示出來。

    那么既然makeKeyAndVisible執(zhí)行的是以上的操作入挣,實際上將[self.window makeKeyAndVisible]替換為self.window.hidden = NO基括,那么界面也會正常顯示出來,因為makeKeyAndVisible內部就是這么做的财岔。但是此時并沒有設置UIApplication的keyWindow风皿,為了以后方便訪問河爹,還是用makeKeyAndVisible更好一點。

    經(jīng)過這一步桐款,界面將要顯示咸这,此時根控制器的view會加到self.window上以正常顯示。

  • 這里有一點要注意:

    系統(tǒng)創(chuàng)建的AppDelegate自帶一個屬性位于.h文件中:

    @property (strong, nonatomic) UIWindow *window;
    

    當用Storyboard的方式加載控制器魔眨,在應用啟動完成的時候(didFinishLaunchingWithOptions)需要一個UIWindow的實例來顯示界面媳维,所以Apple提供了這個window屬性。系統(tǒng)根據(jù)storyboard自動創(chuàng)建一個window遏暴,然后將window賦值給這個window屬性侄刽,以保證完成之后的工作。

    當用代碼的方式加載控制器朋凉,同樣的州丹,首先也需要一個UIWindow的實例來顯示界面,因為不使用Storyboard所以這次要我們自己創(chuàng)建window杂彭。此時有兩種做法墓毒,第一種是在didFinishLaunchingWithOptions方法中創(chuàng)建一個UIWindow對象:

    UIWindow *myWindow = [[UIWindow alloc] initWithFrame:...];
    

    但是如果用這種方法運行程序會發(fā)現(xiàn)界面依然無法顯示出來,因為此時myWindow是一個局部變量亲怠,當didFinishLaunchingWithOptions方法執(zhí)行完畢這個變量就會銷毀所计。所以更好的辦法是直接使用系統(tǒng)提供的window屬性:

    self.window = [[UIWindow alloc] initWithFrame:...];
    

    之前的例子也是這么做的。

    另外团秽,仔細觀察會發(fā)現(xiàn)這個window屬性的修飾符是strong主胧,而不是weak。想想之前使用weak來修飾一個控件是因為這個控件會被加到一個view中习勤,這個view的subViews數(shù)組會有強引用指向控件讥裤,所以用weak是沒有問題的。現(xiàn)在這種情況姻报,因為window控件不會被加到其他view中,即沒有其他的強指針指向這個對象间螟,所以在創(chuàng)建的時候需要將修飾符設置成strong以保證創(chuàng)建出的window不會被銷毀吴旋。(Apple創(chuàng)建的window屬性的修飾符是strong

UIWindow的補充

window是有層級的,并且可以有多個window同時存在厢破。比如:狀態(tài)欄就是一個window荣瑟,鍵盤也是一個window。

可以通過設置UIWindow的對象的windowLevel屬性來調整層級摩泪。

self.window.windowLevel = UIWindowLevelStatusBar;

window共有三種等級:UIWindowLevelNormal笆焰,UIWindowLevelStatusBar UIWindowLevelAlert。如果三種等級同時出現(xiàn)在屏幕上见坑,那么alert在最上面嚷掠,statusBar在中間捏检,normal則在最下面。

注意:如果一個程序中有多個window,控制器默認會把狀態(tài)欄隱藏不皆。

解決辦法:關閉控制器對狀態(tài)欄的控制贯城,(為Info.plist增加View controller-based status bar appearance這個key并設置為NO)這樣這些window以及狀態(tài)欄就可以按層級關系正常顯示。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末霹娄,一起剝皮案震驚了整個濱河市能犯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌犬耻,老刑警劉巖踩晶,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枕磁,居然都是意外死亡渡蜻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門透典,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晴楔,“玉大人,你說我怎么就攤上這事峭咒∷捌” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵凑队,是天一觀的道長则果。 經(jīng)常有香客問我,道長漩氨,這世上最難降的妖魔是什么西壮? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮叫惊,結果婚禮上款青,老公的妹妹穿的比我還像新娘。我一直安慰自己霍狰,他們只是感情好抡草,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蔗坯,像睡著了一般康震。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上宾濒,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天腿短,我揣著相機與錄音,去河邊找鬼。 笑死橘忱,一個胖子當著我的面吹牛赴魁,可吹牛的內容都是我干的。 我是一名探鬼主播鹦付,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼尚粘,長吁一口氣:“原來是場噩夢啊……” “哼嫉称!你這毒婦竟也來了长已?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤哮内,失蹤者是張志新(化名)和其女友劉穎祈噪,沒想到半個月后泽铛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡辑鲤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年盔腔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片月褥。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡弛随,死狀恐怖,靈堂內的尸體忽然破棺而出宁赤,到底是詐尸還是另有隱情舀透,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布决左,位于F島的核電站愕够,受9級特大地震影響,放射性物質發(fā)生泄漏佛猛。R本人自食惡果不足惜惑芭,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望继找。 院中可真熱鬧遂跟,春花似錦、人聲如沸婴渡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缩搅。三九已至,卻和暖如春触幼,著一層夾襖步出監(jiān)牢的瞬間硼瓣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留堂鲤,地道東北人亿傅。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像瘟栖,于是被迫代替她去往敵國和親葵擎。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容