一. 关于UIWindow
- UIWindow是一种特殊的UIView,通常在一个app中只会有一个UIWindow。
- iOS程序启动完毕后,创建的第一个视图控件就是UIWindow,接着创建控制器,再创建控制器的view,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上了。
- 一个iOS程序之所以能显示到屏幕上,完全是因为它有UIWindow,也就是说,没有UIWindow,就看不见任何UI界面。
- UIWindow是创建的第一个视图控件,UIapplication是创建的第一个对象。
文档中关于该部分的解释:
二. UIWindow的使用
1. 创建window
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
2. 把view添加到window上
创建一个控制器,把view添加到window上面,有两种方式:
方式1:
直接将控制器的view添加到window中,并不理会它对应的控制器
[self.window addsubview:vc.view];
方式2:推荐
设置window的根控制器,自动将rootviewcontroller的view添加到window中,负责管理rootviewcontroller的生命周期(推荐这种方式)。
[self.window.rootviewcontroller = vc];
方式1的问题:
问题1:当view发生一些事件的时候,通知控制器,但是控制器已经销毁了,所以可能出现未知的错误。比如说控制器上面可能有按钮,需要监听按钮的点击事件,如果是1,那么按钮的事件应该由控制器来进行管理,但控制器是一个局部变量,控制器此时已经不存在了,但是控制器的view还在,此时有可能会报错。
问题2:添加一个开关按钮,让屏幕360度旋转,当发生屏幕旋转事件的时候,UIapplication对象会将旋转事件传递给window,window又会将旋转事件传递给它的根控制器,由根控制器决定是否需要旋转,如下:
UIapplication->UIWindow->根控制器,由于第一种方式没有根控制器,所以不能跟着旋转。
三. UIWindow的创建过程
1. 有storyboard
- 为什么创建一个storyboard,没有看到创建window的过程?
它其实是把创建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的初始化的文档:
2. 没有storyboard
先执行Main函数,执行UIApplicationMain(),根据其第三个和第四个参数创建Application,创建代理,并且把代理设置给application,开启一个事件循环,当程序加载完毕,他会调用代理的didFinishLaunchingWithOptions:方法。在该方法中,会创建一个Window,然后创建一个控制器,并把该控制器设置为UIWindow的根控制器,接下来再将window显示出来,即看到了运行后显示的界面。
四. 主窗口
1. 设置主窗口
[self.window makekeyandvisible]
让窗口成为主窗口,并且显示出来。有这个方法,才能把信息显示到屏幕上。
因为window有makekeyandvisible这个方法,可以让这个window凭空的显示出来,而其他的view没有这个方法,所以它只能依赖于window,window显示出来后,view才依附在window上显示出来。
一个应用程序中只能有一个主窗口,如果程序中设置了两个主窗口,后面的主窗口能覆盖前面的主窗口。
[self.window make keywindow]
让window成为主窗口,但不显示。
2. 获取window
[UIApplication sharedApplication].windows;
在本应用中打开的UIWindow列表,这样就可以获取应用中的任何一个UIView对象,平时输入文字弹出的键盘,就处在一个新的UIWindow中。
[UIApplication sharedApplication].keyWindow;
获取应用程序的主窗口,而且程序中每个时刻只能有一个window是keyWindow。
UIWindow *viewWindow = view.window;
获得某个UIView所在的UIWindow。
五. UIWindow的用处
在IOS应用中,我们使用UIWindow和UIView来呈现界面。UIWindow并不包含任何默认的内容,它被当做UIView的容器,用于放置应用中所有的UIView。从继承关系来看,UIWindow继承自UIView,所以UIWIndow除了具有UIView的所有功能外,还增加了一些特有的属性和方法。
UIWindow的主要作用:
- 作为UIView的最顶层容器,包含应用显示所需要的所有UIView
- 传递触摸消息和键盘事件给UIView
关于系统对UIWindow的使用:
通常在一个程序中只会有一个UIWindow,但有些时候我们调用系统的控件(例如UIAlertView)时,IOS系统为了保证UIAlertView在所有的界面之上,它会临时创建一个新的UIWindow,通过将其UIWindow的UIWindowLevel设置的更高,让UIWindow盖在所有的应用界面之上(熟悉html的朋友应该知道,网页上面的“遮罩效果”,就是通过设置元素的z-index属性,来控制层级的上下关系,是一个道理)。