iOS:App啟動過程詳解


以上是Xcode4.2中不采用storyboard應用的默認啟動流程圖。對於采用了storyboard的應用,UIApplicationMain()

將會額外加載應用的主要storyboard文件,從而創建窗口和初始視圖。

 

程序啟動的完整過程

1.main函數

2.UIApplicationMain

* 創建UIApplication對象

* 創建UIApplication的delegate對象

 

3.delegate對象開始處理(監聽)系統事件(沒有storyboard)

* 程序啟動完畢的時候, 就會調用代理的application:didFinishLaunchingWithOptions:方法

* 在application:didFinishLaunchingWithOptions:中創建UIWindow

* 創建和設置UIWindow的rootViewController

* 顯示窗口

 

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

* 創建UIWindow

* 創建和設置UIWindow的rootViewController

* 顯示窗口

 

 

一、UIApplicationMain這個函數主要負責三件 事情: 

1)從給定的類名初始化應用程序對象,也就是初始化UIApplication或者子類對象的一個實例,如果你在這里給定的是nil,那么 系統會默認UIApplication類,也就主要是這個類來控制以及協調應用程序的運行。在后續的工作中,你可以用靜態方法sharedApplication 來獲取應用程序的句柄。 
 

2)從給定的應用程序委托類,初始化一個應用程序委托(UIApplicationDelegate)。並把該委托設置為應用程序的委托,這里就有如果傳入參數為nil,會調用函數訪問 Info.plist文件來尋找主nib文件,獲取應用程序委托。 
 

3)啟動主事件循環,並開始接收事件。

 

二、UIApplication(或 者子類)對象的職責,這個對象主要做下面幾件事: 
 

1)負責處理到來的用戶事件並分發事件消息到應該處理該消息的目標對象(sender,  action)。 


 2)管理以及控制視圖,包括呈現、控制行為、當前顯示視圖等。 


 3)該對象有一個應用程序委托對象,當一些生命周期內重要事件(可以包括系統事件或者生命周期控制事件)發生時,應用程序通知該對象。例如,應用程序啟 動、內存不夠了或者應用程序結束等,讓這些事件發生時,應用程序委托去響應。 

UIApplication有以下成員變量
    1、sharedApplication類方法獲取當前程序的UIApplication實例
    2、delegate屬性獲取UIApplicationDelegate實現類的實例
    3、windows屬性獲取當前程序涉及到窗口類數組 
    4、keyWindow屬性獲取當前程序關鍵窗口

所以當前的windows存放在UIApplication中。

 

 

以上流程圖是沒有加載sb的,以下是加載sb的流程:

-.先執行main函數,main內部會調用UIApplicationMain函數
--.UIApplicationMain函數里面做了什么事情:
1.調用UIApplicationMain()函數;
2.創建UIApplication對象;
3.創建UIApplication的delegate對象-----XXAppDelegate;
4.加載Info.plist文件,讀取最主要storyboard文件的名稱;
5.UIApplication開啟一個消息循環
* 每監聽到對應的系統事件時,就會通知MJAppDelegate;
6.UIApplication調用相關代理方法;
------------我是分割線------------
7.為應用程序創建一個 UIWindow對象(繼承自UIView), 設置為XXAppDelegate的window屬性;
8.加載最主要的storyboard文件,創建白色箭頭所指的控制器對象;
9.並且將8步奏里創建的控制器為UIWindow的rootViewController屬性(根控制器);
10.展示UIWindow,展示之前會將添加rootViewController的view到UIWindow上面(在這一步才會創建控制器的view)
    [window addSubview: window.rootViewControler.view];
------------end------------
 
  ** 用例1**:不使用storyboard,程序啟動后進入application:didFinishLaunchingWithOptions方法,該方法內部什么都不實現
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // Override point for customization after application launch.    
  3.     return YES;  
  4. }  
      結果:程序啟動,屏幕一片漆黑。
       用例1分析:程序啟動,didFinishLaunchingWithOptions方法里沒有加載任何視圖(還有window原因,見下面用例)。
      ** 用例2**:不使用storyboard,程序啟動后進入application:didFinishLaunchingWithOptions方法,該方法內部創建添加需要顯示的內容。
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // Override point for customization after application launch.  
  3.      
  4.     TableViewController *tableViewController = [[TableViewController alloc]initWithStyle:UITableViewStylePlain];      
  5.     [self.window addSubview:tableViewController.view];      
  6.     [self.window makeKeyAndVisible];  
  7.     return YES;  
  8. }  
      結果:程序啟動,屏幕一片漆黑
      ** 用例3**:不使用storyboard,程序啟動后進入application:didFinishLaunchingWithOptions方法,該方法內部創建UIWindow,並創建添加需要顯示的內容。
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // Override point for customization after application launch.  
  3.       
  4.     self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];  
  5.     TableViewController *tableViewController = [[TableViewController alloc]initWithStyle:UITableViewStylePlain];      
  6.     [self.window addSubview:tableViewController.view];      
  7.     [self.window makeKeyAndVisible];  
  8.     return YES;  
  9. }  
       結果:程序啟動,顯示tableviewController的視圖,正常。
        用例2+用例3分析:當不用storyboard的時候,AppDelegate被創建完之后,它的window屬性為空,需要手動創建之。然后再用它
      ** 用例4**:使用storyboard,程序啟動后進入application:didFinishLaunchingWithOptions方法,該方法內部創建添加需要顯示的內容
        (備注:storyboard里面初始化的控制器為ViewController,並且在相關方法輸出了_cmd)
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // Override point for customization after application launch.  
  3.      
  4.     NSLog(@"here1");  
  5.     NSLog(@"%@",self.window);  
  6.     TableViewController *tableViewController = [[TableViewController alloc]initWithStyle:UITableViewStylePlain];    
  7.     NSLog(@"here2");    
  8.     [self.window addSubview:tableViewController.view];  
  9.     NSLog(@"here3");  
  10.     return YES;  
  11. }  
        結果:輸出,界面顯示ViewController的界面
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. 2014-09-20 16:30:22.066 Refer[3253:60b] ViewController : initWithCoder:  
  2. 2014-09-20 16:30:22.074 Refer[3253:60b] here1  
  3. 2014-09-20 16:30:22.077 Refer[3253:60b] <UIWindow: 0x14db9020; frame = (0; 32480); hidden = YES; gestureRecognizers = <NSArray: 0x14db9cb0>; layer = <UIWindowLayer: 0x14dbb910>>  
  4. 2014-09-20 16:30:22.079 Refer[3253:60b] here2  
  5. 2014-09-20 16:30:22.091 Refer[3253:60b] TableViewController : viewDidLoad  
  6. 2014-09-20 16:30:22.095 Refer[3253:60b] here3  
  7. 2014-09-20 16:30:22.104 Refer[3253:60b] ViewController : viewDidLoad  
        分析用例4:tableviewController的界面不顯示,可能是被viewController界面覆蓋了,還是某種原因。
     ** 用例5**:使用storyboard,程序啟動后進入application:didFinishLaunchingWithOptions方法,該方法內部創建添加需要顯示的內容
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  
  2.     // Override point for customization after application launch.  
  3.      
  4.     NSLog(@"here1");  
  5.     NSLog(@"%@",self.window);  
  6.     NSLog(@"%@",self.window.rootViewController);  
  7.     TableViewController *tableViewController = [[TableViewController alloc]initWithStyle:UITableViewStylePlain];  
  8.     NSLog(@"here2");    
  9.     [self.window setRootViewController:tableViewController];   
  10.     // or [self.window.rootViewController.view addSubview:tableViewController.view];  
  11.     NSLog(@"here3");  
  12.     return YES;  
  13. }  
        結果:輸出,界面顯示tableviewController的界面
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. 2014-09-20 16:40:14.135 Refer[3260:60b] ViewController : initWithCoder:  
  2. 2014-09-20 16:40:14.143 Refer[3260:60b] here1  
  3. 2014-09-20 16:40:14.146 Refer[3260:60b] <UIWindow: 0x16e5f570; frame = (0; 32480); hidden = YES; gestureRecognizers = <NSArray: 0x16e5fc10>; layer = <UIWindowLayer: 0x16e5f650>>  
  4. 2014-09-20 16:40:14.148 Refer[3260:60b] <ViewController: 0x16da9be0>  
  5. 2014-09-20 16:40:14.150 Refer[3260:60b] here2  
  6. 2014-09-20 16:40:14.153 Refer[3260:60b] here3   
  7. 2014-09-20 16:40:14.167 Refer[3260:60b] TableViewController : viewDidLoad  
       結果(當執行or里面的語句)輸出,界面顯示tableviewController的界面
[objc]  view plain copy 在CODE上查看代碼片 派生到我的代碼片
  1. 014-09-20 16:43:21.707 Refer[3268:60b] ViewController : initWithCoder:  
  2. 2014-09-20 16:43:21.716 Refer[3268:60b] here1  
  3. 2014-09-20 16:43:21.718 Refer[3268:60b] <UIWindow: 0x16d88720; frame = (0; 32480); hidden = YES; gestureRecognizers = <NSArray: 0x16e7a1b0>; layer = <UIWindowLayer: 0x16d8c2b0>>  
  4. 2014-09-20 16:43:21.720 Refer[3268:60b] <ViewController: 0x16d8a170>  
  5. 2014-09-20 16:43:21.722 Refer[3268:60b] here2  
  6. 2014-09-20 16:43:21.731 Refer[3268:60b] ViewController : viewDidLoad // <span style="color:#cc0000;">因為調用到了它</span>  
  7. 2014-09-20 16:43:21.741 Refer[3268:60b] TableViewController : viewDidLoad  
  8. 2014-09-20 16:43:21.743 Refer[3268:60b] here3  
        分析用例5: 當info.plist里面有值時,程序先加載storyboard中的對象,並創建之,之后創建AppDelegate的window,並且將初始控制器賦值給window的rootViewController,然后調用application:didFinishLaunchingWithOptions方法
說明:
1.window的rootViewController會覆蓋windows上的子視圖。
2. 如果使用storyboard的情況下,[self.window makeKeyAndVisible]方法會在方法application:didFinishLaunchingWithOptions結束后,隱式調用;當然也可以顯示調用,window提前顯示到了屏幕上。例如上面用例結果1,如果[self.window makeKeyAndVisible]顯示寫在 NSLog(@"here3");之前,則 輸出“TableViewController : viewDidLoad” 在“here3”之前
-------結論:
         使用storyboard的時候,先創建storyboard里面對象,和appDelegate的window,之后調用相關代理方法didFinish...,之后如果需要再調用[makeKeyAndVisible]
--------------備注--------------
           a.關於Application如何查找對應的plist文件?  當一個target創建完,它自動關聯了一個plist文件(名字一般是target.plist),如果我們修改了該plist文件名或者該文件被刪除,導致target找不到該plist文件,則進入target info界面的時候要要求選擇 plist文件,如下圖:
 
原文參見http://blog.csdn.net/houseq/article/details/38312281

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM