一、簡單介紹
UIWindow是一種特殊的UIView,通常在一個app中只會有一個UIWindow
iOS程序啓動完畢後,創建的第一個視圖控件就是UIWindow,接着創建控制器的view,最後將控制器的view添加到UIWindow上,於是控制器的view就顯示在屏幕上了
一個iOS程序之所以能顯示到屏幕上,完全是因爲它有UIWindow。也就說,沒有UIWindow,就看不見任何UI界面
補充:UIWindow是創建的第一個視圖控件(創建的第一個對象是UIapplication)如下圖:
添加
先創建UIwindow,再創建控制器,創建控制器的view,然後將控制器的view添加到UIWindow上。
文檔中關於該部分的解釋:
二、UIWindow的創建過程
1.簡單說明
創建一個空的項目,就可以看到UIWindow是怎麼出來的了。在程序啓動完畢之後就會調用一次,創建過程如下:
提示:應用程序啓動之後,先創建Application,再創建它的代理,之後創建UIwindow。UIWindow繼承自UIview。
2.把view添加到uiwindow
創建一個控制器,把view添加到uiwindow上面(有兩種方式)
(1)直接將控制器的view添加到UIWindow中,並不理會它對應的控制器
[self.window addsubview:vc.view];
(2)設置uiwindow的根控制器,自動將rootviewcontroller的view添加到window中,負責管理rootviewcontroller的生命週期
[self.window.rootviewcontroller=vc];
兩個方法的區別:
以後的開發中,建議使用(2).因爲方法(1)存在一些問題,比如說控制器上面可能由按鈕,需要監聽按鈕的點擊事件,如果是1,那麼按鈕的事件應該由控制器來進行管理。但控制器是一個局部變量,控制器此時已經不存在了,但是控制器的view還在,此時有可能會報錯。注意:方法執行完,這個控制器就已經不存在了。
問題描述1:當view發生一些事件的時候,通知控制器,但是控制器已經銷燬了,所以可能出現未知的錯誤。
問題描述2:添加一個開關按鈕,讓屏幕360度旋轉(兩者的效果不一樣)。當發生屏幕旋轉事件的時候,UIapplication對象會將旋轉事件傳遞給uiwindow,uiwindow又會將旋轉事件傳遞給它的根控制器,由根控制器決定是否需要旋轉
UIapplication->uiwindow->根控制器(第一種方式沒有根控制器,所以不能跟着旋轉)。
提示:不通過控制器的view也可以做開發,但是在實際開發中,不要這麼做,不要直接把view添加到UIWindow上面去。因爲,難以管理。
3.在有storyboard的項目中,UIWindow是如何創建的?
爲什麼創建一個storyboard,沒有看到創建uiwindow的過程?
它其實是把創建UIWindow的過程給屏蔽起來了。可以把代理的UIWindow的屬性的值打印出來NSLog(@“window=%p”,self.window);打印出來確實是有值的,說明確實創建了UIWindow.不僅創建了UIWindow,默認還創建了UIWindow對應的控制器,也可以打印進行查看。NSLog(@“%@“,self.window.rootviewcontroller);
有storyboard的項目中的創建過程:
當用戶點擊應用程序圖標的時候,先執行Main函數,執行UIApplicationMain(),根據其第三個和第四個參數創建Application,創建代理,並且把代理設置給application(看項目配置文件info.plist裏面的storyboard的name,根據這個name找到對應的storyboard),開啓一個事件循環,當程序加載完畢,他會調用代理的didFinishLaunchingWithOptions:方法。在調用didFinishLaunchingWithOptions:方法之前,會加載storyboard,在加載的時候創建一個window,接下來會創建箭頭所指向的控制器,把該控制器設置爲UIWindow的根控制器,接下來再將window顯示出來,即看到了運行後顯示的界面。(提示:關於這部分可以查看story的初始化的文檔)
三、如何獲取window?
1.主窗口和次窗口
【self.window makekeyandvisible】讓窗口成爲主窗口,並且顯示出來。有這個方法,才能把信息顯示到屏幕上。
因爲Window有makekeyandvisible這個方法,可以讓這個Window憑空的顯示出來,而其他的view沒有這個方法,所以它只能依賴於Window,Window顯示出來後,view才依附在Window上顯示出來。
【self.window make keywindow】//讓uiwindow成爲主窗口,但不顯示。
2.獲取UIwindow
(1)[UIApplication sharedApplication].windows 在本應用中打開的UIWindow列表,這樣就可以接觸應用中的任何一個UIView對象(平時輸入文字彈出的鍵盤,就處在一個新的UIWindow中)
(2)[UIApplication sharedApplication].keyWindow(獲取應用程序的主窗口)用來接收鍵盤以及非觸摸類的消息事件的UIWindow,而且程序中每個時刻只能有一個UIWindow是keyWindow。
提示:如果某個UIWindow內部的文本框不能輸入文字,可能是因爲這個UIWindow不是keyWindow
(3)view.window獲得某個UIView所在的UIWindow
四、四大對象的關係圖
五、主窗口和次窗口說明
代碼:01.
//
程序啓動完畢之後就會調用一次
02.
-
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
03.
{
04.
//
1.創建UIWindow
05.
self.window
= [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
06.
//
設置UIWindow的背景顏色
07.
self.window.backgroundColor
= [UIColor redColor];
08.
09.
//
讓UIWindow顯示出來(讓窗口成爲主窗口 並且顯示出來)
10.
//
一個應用程序只能有一個主窗口
11.
[self.window
makeKeyAndVisible];
12.
//
讓UIWindow成爲主窗口
13.
//
[self.window makeKeyWindow];
14.
15.
//
2. 再創建一個窗口
16.
UIWindow
*w2 = [[UIWindow alloc] initWithFrame:CGRectMake(
100
,
100
,
200
,
200
)];
17.
w2.backgroundColor
= [UIColor yellowColor];
18.
[w2
makeKeyAndVisible];
19.
self.w2
= w2;
20.
21.
22.
//
3.創建兩個文本輸入框
23.
//
3.1將文本輸入框添加到window中
24.
UITextField
*tx1 = [[UITextField alloc] initWithFrame:CGRectMake(
10
,
10
,
200
,
40
)];
25.
tx1.borderStyle
= UITextBorderStyleRoundedRect;
26.
[self.window
addSubview:tx1];
27.
28.
//
3.2將文本輸入框添加到w2中
29.
UITextField
*tx2 = [[UITextField alloc] initWithFrame:CGRectMake(
10
,
10
,
100
,
40
)];
30.
tx2.borderStyle
= UITextBorderStyleRoundedRect;
31.
[self.w2
addSubview:tx2];
32.
33.
34.
//
獲取應用程序的主窗口
35.
NSLog(@
"%@"
,
[UIApplication sharedApplication].keyWindow);
36.
return
YES;
37.
}