国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

詳解iOS應(yīng)用程序的啟動過程

2020-07-26 03:25:24
字體:
供稿:網(wǎng)友

關(guān)鍵步驟
一個程序從main函數(shù)開始啟動。

復(fù)制代碼 代碼如下:

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

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

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

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

  • 根據(jù)傳入的名稱創(chuàng)建UIApplication對象。
  • 根據(jù)傳入的代理名稱創(chuàng)建UIApplication代理對象。
  • 開啟事件循環(huán)(如果不進(jìn)行循環(huán),那么在main函數(shù)結(jié)束后程序就結(jié)束了。要保證程序創(chuàng)建后可以一直存在)。
  • 解析Info.plist文件:

會在Info.plist文件里查找Main storyboard file base name這個Key對應(yīng)的Value是否有值。如果有值,則表示之后會通過Storyboard加載控制器,AppDelegate會接收到didFinishLaunchingWithOptions消息(程序啟動完成的時候),此時Storyboard會進(jìn)行一系列的加載操作(后面會具體說);如果沒有值,則不會通過Storyboard加載控制器,接著AppDelegate會接收到didFinishLaunchingWithOptions消息(程序啟動完成的時候),在這個時候需要我們通過代碼的方式加載控制器。

注意Info.plist中Main storyboard file base name這個Key并不是真正的Key,而是蘋果為了增強(qiáng)可讀性才這樣寫的,真正的Key為UIMainStoryboardFile(可以通過Info.plist文件的源代碼查看)。
這就是在想要用代碼方式創(chuàng)建控制器而不是Storyboard創(chuàng)建控制器的時候?yàn)槭裁聪纫獙ain Interface設(shè)置為空白,這樣在解析Info.plist文件的時候才會知道不通過Storyboard創(chuàng)建控制器。
由此可以知道,解析Info.plist文件這一操作主要是看我們用的是Storyboard方式加載還是代碼的方式加載。默認(rèn)Main storyboard file base name為Main,也就是通過Storyboard方式加載控制器。
現(xiàn)在具體分析一下,通過Storyboard方式加載控制器和代碼方式加載控制器。

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

創(chuàng)建窗口。

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

設(shè)置窗口的根控制器。

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

設(shè)置self.window可見并且設(shè)置UIApplication的keyWindow。

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

通過代碼方式
通過代碼的方式,需要我們在didFinishLaunchingWithOptions方法中進(jìn)行加載控制器的相關(guān)操作。

復(fù)制代碼 代碼如下:

- (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;
}


其實(shí)這里所做和系統(tǒng)所做是一樣的。(相當(dāng)于系統(tǒng)的做法)

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

接著設(shè)置窗口的根控制器。

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

復(fù)制代碼 代碼如下:

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

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

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

復(fù)制代碼 代碼如下:

self.window.hidden = NO;

這么做的原因是self.window默認(rèn)hidden = YES,所以需要讓其顯示出來。

那么既然makeKeyAndVisible執(zhí)行的是以上的操作,實(shí)際上將[self.window makeKeyAndVisible]替換為self.window.hidden = NO,那么界面也會正常顯示出來,因?yàn)閙akeKeyAndVisible內(nèi)部就是這么做的。但是此時并沒有設(shè)置UIApplication的keyWindow,為了以后方便訪問,還是用makeKeyAndVisible更好一點(diǎn)。

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

這里有一點(diǎn)要注意:

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

復(fù)制代碼 代碼如下:

@property (strong, nonatomic) UIWindow *window;

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

當(dāng)用代碼的方式加載控制器,同樣的,首先也需要一個UIWindow的實(shí)例來顯示界面,因?yàn)椴皇褂肧toryboard所以這次要我們自己創(chuàng)建window。此時有兩種做法,第一種是在didFinishLaunchingWithOptions方法中創(chuàng)建一個UIWindow對象:

復(fù)制代碼 代碼如下:

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

但是如果用這種方法運(yùn)行程序會發(fā)現(xiàn)界面依然無法顯示出來,因?yàn)榇藭rmyWindow是一個局部變量,當(dāng)didFinishLaunchingWithOptions方法執(zhí)行完畢這個變量就會銷毀。所以更好的辦法是直接使用系統(tǒng)提供的window屬性:
復(fù)制代碼 代碼如下:

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

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

另外,仔細(xì)觀察會發(fā)現(xiàn)這個window屬性的修飾符是strong,而不是weak。想想之前使用weak來修飾一個控件是因?yàn)檫@個控件會被加到一個view中,這個view的subViews數(shù)組會有強(qiáng)引用指向控件,所以用weak是沒有問題的。現(xiàn)在這種情況,因?yàn)閣indow控件不會被加到其他view中,即沒有其他的強(qiáng)指針指向這個對象,所以在創(chuàng)建的時候需要將修飾符設(shè)置成strong以保證創(chuàng)建出的window不會被銷毀。(Apple創(chuàng)建的window屬性的修飾符是strong)

UIWindow的補(bǔ)充
window是有層級的,并且可以有多個window同時存在。比如:狀態(tài)欄就是一個window,鍵盤也是一個window。

可以通過設(shè)置UIWindow的對象的windowLevel屬性來調(diào)整層級。

self.window.windowLevel = UIWindowLevelStatusBar;
window共有三種等級:UIWindowLevelNormal,UIWindowLevelStatusBar UIWindowLevelAlert。如果三種等級同時出現(xiàn)在屏幕上,那么alert在最上面,statusBar在中間,normal則在最下面。

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

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

概覽
這里PY為前綴名:

1.先執(zhí)行main函數(shù),main內(nèi)部會調(diào)用UIApplicationMain函數(shù)

2.UIApplicationMain函數(shù)里面做了什么事情:

(1)創(chuàng)建UIApplication對象

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

主站蜘蛛池模板: 黄骅市| 三江| 福鼎市| 兴安盟| 利津县| 仁布县| 万盛区| 黔南| 保德县| 永丰县| 阳新县| 临夏市| 岢岚县| 应用必备| 宁河县| 景东| 香港| 潍坊市| 保德县| 军事| 阜新市| 皮山县| 射阳县| 始兴县| 南江县| 彩票| 麦盖提县| 广东省| 会泽县| 敦煌市| 山西省| 临汾市| 陇南市| 修水县| 陵水| 潍坊市| 浏阳市| 徐汇区| 百色市| 秀山| 云安县|