UIViewiOS可视化图形界面开发所使用的基类,并负责响应用户的交互行为;

UIWindow是包含图形界面的窗口,它是一切可视化界面的容器(使用Reveal可以得到验证),并且它还将持续跟踪App当前的firstResponder(第一响应者),并负责处理由Application对象传递过来的消息(依据其 sendEvent实例方法的文档注释可以得出,亦即response chain(响应链)的开端);

UIScreen是硬件设备屏幕的抽象,因此它会包含所有的UIWindow实例,通常会用mainScreenbounds属性来初始化一个适合屏幕大小的key window(主窗口),因为官方文档明确说明UIWindow是无法响应在其bounds之外的触摸事件的,对用户而言就是其触屏事件将得不到响应。

以上是关于它们三兄弟我们认知的比较清楚的一些知识点,但前两者在使用上的区别我们有必要做进一步深究。而对于UIScreen的其他使用,比如mirrored,我想它也是蛮有意思的。这一切的思考源自我对项目中关于截屏触发的反馈界面是应该使用UIWindow还是UIView,系统状态栏和键盘为什么是*Window而不是*View

从文档入手

虽然我们曾多次吐槽Apple文档的啰嗦,但也不可否认它们将开发的流程描述得足够清楚。不过我想,真正能够将官方所有的开发文档阅读完的朋友少之又少。因为文档的体量还是有点大,同时我们平常负责开发的App只会用到其中的一部分知识。如果出现了“书到用时方恨少”这种窘境(当然也有可能是属于自然遗忘),我们不妨现炒现卖。

You use windows only when you need to do the following:

Provide a main window to display your app’s content.

Create additional windows (as needed) to display additional content.

一句mmp不知当讲不当讲!这和没说有什么分别!然后再把这里逛完一周,发现依然只是对它们的使用更加了解罢了(这个文档其实非常值得一看,😅,里面有对App多屏联动的实现较为具体的阐述,相信你看完之后就能自己写一个Time Out了。)。看来只有靠自己了,为了减少以后被下属或者上司,甚至是面试官问到为什么有时候要用UIWindow而不用UIView的原因时脸上的茫然,YY吧!

主观臆测

举一个我们都曾遇到过的🌰:键盘管理。暂且抛开IQKeyboardManager,实现一个简单的功能,也就是键盘挡住输入框多少,我就把输入框上移多少。无疑,我们会先注册一个通知:UIKeyboardDidShowNotification,然后在此通知响应方法里面获取键盘视图的frame(notification.userInfo[@"UIKeyboardFrameEndUserInfoKey"]),最后判断它与输入框的frame是否有交集,并通过调整输入框frame中的origin.y来达到目的。但别忘了,键盘的frame是相当于它的容器窗口来计算的,所以你还需要将输入框的frame变换到UIWindow上,这样它与键盘才有可比性。这里也就引出了UIWindow的另外一个用处:相对于全屏幕的坐标变换,那么这里会自然思考键盘视图为什么是由另一个*Window来管理,而不直接追加到最上层的视图呢?相信通过我这样的表述(YY),你会有此一问。

如果键盘视图是以subview的方式添加到当前应用最上层的视图,那么在弹出键盘之前,系统还得通过key windowroot view controller不断地顺藤摸瓜(例如使用类似响应链的方式)。归根结底,这太麻烦了,浪费时间啊!特别是对于这种一定要响应及时的UI操作,任何一点时间的消耗都可能影响用户体验。而使用*Window则根本不需要关心这些,我只需要调整下window level(实质上是z轴的坐标)就行了。而对于status bar来说就更是如此了,在系统界面需要出现,在App的界面也需要出现。如果你用subview的方式,那你得做多少次添加或删除或移动的操作啊!它和键盘本身是一个典型的单例,谁要用我就展示出来好了,大不了再根据App的界面配置更改下外观不就行了。相比于Android,这还带来了沉浸式的阅读体验,因为它们并没有那么明显的分块区隔,而是通过分层合成的(现在每每看到Android手机那独立出来的状态栏就糟心)。类比来说,你要让人在一张纸上堆叠出绚丽的特效,相信没人敢接手!为什么?因为一个差错就全部都不能用了啊,而用分层的思想,我就可以分开来单独渲染。一个环节只会影响到当前这一层,而对全局没有毒副作用。

嗯,道理是相通的,分而治之,😅