症結步調
一個法式從main函數開端啟動。
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
可以看到main函數會挪用UIApplicationMain函數,它的四個參數的意思是:
在UIApplicationMain函數中,依據傳入的UIApplication稱號和它的署理的稱號,會重要做上面的工作:
會在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運用法式的啟動進程】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!