你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> 詳解iOS運用法式的啟動進程

詳解iOS運用法式的啟動進程

編輯:IOS開發綜合

症結步調
一個法式從main函數開端啟動。

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

可以看到main函數會挪用UIApplicationMain函數,它的四個參數的意思是:

  • argc: 代表法式在進入main函數時的參數的個數。默許為1。
  • argv: 代表包括的各個參數。默許為法式的名字。
  • principalClassName: UIApplication或許它的子類的名字, 假如傳入的是nil, 則表現UIApplication的名字, 即@"UIApplication"。
  • delegateClassName: UIApplication的署理的名字。

在UIApplicationMain函數中,依據傳入的UIApplication稱號和它的署理的稱號,會重要做上面的工作:

  • 依據傳入的稱號創立UIApplication對象。
  • 依據傳入的署理稱號創立UIApplication署理對象。
  • 開啟事宜輪回(假如不停止輪回,那末在main函數停止後法式就停止了。要包管法式創立後可以一向存在)。
  • 解析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文件的源代碼檢查)。
這就是在想要用代碼方法創立掌握器而不是Storyboard創立掌握器的時刻為何先要將Main Interface設置為空白,如許在解析Info.plist文件的時刻才會曉得欠亨過Storyboard創立掌握器。
由此可以曉得,解析Info.plist文件這一操作重要是看我們用的是Storyboard方法加載照樣代碼的方法加載。默許Main storyboard file base name為Main,也就是經由過程Storyboard方法加載掌握器。
如今詳細剖析一下,經由過程Storyboard方法加載掌握器和代碼方法加載掌握器。

經由過程Storyboard
經由過程Storyboard,重要做了上面的工作(這些工作不須要我們做,是體系主動完成的,在法式啟動完成的時刻):

創立窗口。

創立一個UIWindow的實例用來顯示界面。

設置窗口的根掌握器。

依據Storyboard的設置,創立一個掌握器。
而且設置這個掌握器為之前創立的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;
}

其實這裡所做和體系所做是一樣的。(相當於體系的做法)

起首創立窗口,獲得一個准確的UIWindow實例對象用來顯示界面。(self.window是體系自帶的屬性)

接著設置窗口的根掌握器。

不再依據Storyboard中的設置加載,此時須要我們本身創立掌握器。
設置這個掌握器為self.window的根掌握器。
留意這個時刻根掌握器的view還沒有加到self.window上,當窗口要顯示的時刻,才會把窗口的根掌握器的view添加到窗口。(可以輸入self.window.subViews來驗證)
顯示窗口。

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

起首,將self.window設置為UIApplication的keyWindow,這麼做是便利我們今後檢查UIApplication的主窗口是哪個。

接著,讓self.window可見,相當於履行的代碼是:

self.window.hidden = NO;

這麼做的緣由是self.window默許hidden = YES,所以須要讓其顯示出來。

那末既然makeKeyAndVisible履行的是以上的操作,現實大將[self.window makeKeyAndVisible]調換為self.window.hidden = NO,那末界面也會正常顯示出來,由於makeKeyAndVisible外部就是這麼做的。然則此時並沒有設置UIApplication的keyWindow,為了今後便利拜訪,照樣用makeKeyAndVisible更好一點。

經由這一步,界面將要顯示,此時根掌握器的view會加到self.window上以正常顯示。

這裡有一點要留意:

體系創立的AppDelegate自帶一個屬性位於.h文件中:

@property (strong, nonatomic) UIWindow *window;

當用Storyboard的方法加載掌握器,在運用啟動完成的時刻(didFinishLaunchingWithOptions)須要一個UIWindow的實例來顯示界面,所以Apple供給了這個window屬性。體系依據storyboard主動創立一個window,然後將window賦值給這個window屬性,以包管完成以後的任務。

當用代碼的方法加載掌握器,異樣的,起首也須要一個UIWindow的實例來顯示界面,由於不應用Storyboard所以此次要我們本身創立window。此時有兩種做法,第一種是在didFinishLaunchingWithOptions辦法中創立一個UIWindow對象:

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

然則假如用這類辦法運轉法式會發明界面仍然沒法顯示出來,由於此時myWindow是一個部分變量,當didFinishLaunchingWithOptions辦法履行終了這個變量就會燒毀。所以更好的方法是直接應用體系供給的window屬性:

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

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

別的,細心不雅察會發明這個window屬性的潤飾符是strong,而不是weak。想一想之前應用weak來潤飾一個控件是由於這個控件會被加到一個view中,這個view的subViews數組會有強援用指向控件,所以用weak是沒有成績的。如今這類情形,由於window控件不會被加到其他view中,即沒有其他的強指針指向這個對象,所以在創立的時刻須要將潤飾符設置成strong以包管創立出的window不會被燒毀。(Apple創立的window屬性的潤飾符是strong)

UIWindow的彌補
window是有層級的,而且可以有多個window同時存在。好比:狀況欄就是一個window,鍵盤也是一個window。

可以經由過程設置UIWindow的對象的windowLevel屬性來調劑層級。

self.window.windowLevel = UIWindowLevelStatusBar;
window共有三種品級:UIWindowLevelNormal,UIWindowLevelStatusBar UIWindowLevelAlert。假如三種品級同時湧現在屏幕上,那末alert在最下面,statusBar在中央,normal則在最上面。

留意:假如一個法式中有多個window,掌握器默許會把狀況欄隱蔽。

處理方法:封閉掌握器對狀況欄的掌握,(為Info.plist增長View controller-based status bar appearance這個key並設置為NO)如許這些window和狀況欄便可以按層級關系正常顯示。

概覽
這裡PY為前綴名:

1.先履行main函數,main外部會挪用UIApplicationMain函數

2.UIApplicationMain函數外面做了甚麼工作:

(1)創立UIApplication對象

(2)創立UIApplication的delegate對象—–PYAppDelegate

(3)開啟一個新聞輪回:每監聽到對應的體系事宜時,就會告訴MJAppDelegate

(4)為運用法式創立一個UIWindow對象(繼續自UIView),設置為PYAppDelegate的window屬性

(5)加載Info.plist文件,讀取最重要storyboard文件的稱號

(6)加載最重要的storyboard文件,創立白色箭頭所指的掌握器對象

(7)而且設置第6步創立的掌握器為UIWindow的rootViewController屬性(根掌握器)

(8)展現UIWindow,展現之前會將添加rootViewController的view到UIWindow下面(在這一步才會創立掌握器的view)

[window addSubview: window.rootViewControler.view];

進入main函數,在main.m的main函數中履行了UIApplicationMain這個辦法,這是IOS法式的進口點!

int UIApplicationMain(int argc, char argv[], NSString principalClassName, NSString *delegateClassName)

argc、argv:ISO C尺度main函數的參數,直接傳遞給UIApplicationMain停止相干處置便可

principalClassName:指定運用法式類,該類必需是UIApplication(或子類)。假如為nil,則用UIApplication類作為默許值

delegateClassName:指定運用法式類的署理類,該類必需遵照UIApplicationDelegate協定

此函數會依據principalClassName創立UIApplication對象,依據delegateClassName創立一個delegate對象,並將該delegate對象賦值給UIApplication對象中的delegate屬性

lUIApplication對象會順次給delegate對象發送分歧的新聞,接著會樹立運用法式的main runloop(事宜輪回),停止事宜的處置(起首會挪用delegate對象的 application:didFinishLaunchingWithOptions:)

法式正常加入時這個函數才前往。假如過程要被體系強迫殺逝世,普通這個函數還沒來得及前往過程就終止了

上面我們有圖有本相吧!!!

【詳解iOS運用法式的啟動進程】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved