工作中需要制作一个ActionView,为了良好的封装性,使用一定要极为方便: XxxActionSheet.show()
显示, XxxActionSheet.dismiss()
隐藏。
所以对于任意视图呈现的View,我们应该能很自然地想到要添加到window上。
以前看到过别人写的博客,通过 UIApplication.sharedApplication().windows.last
来获得当前的 window
。
在苹果官方提供的文档,对 windows
数组的描述:
Discussion
This property contains the UIWindow objects currently associated with the app. This list does not include windows created and managed by the system, such as the window used to display the status bar.
The windows in the array are ordered from back to front by window level; thus, the last window in the array is on top of all other app windows.
总结一下这段文档的意思就是, windows
属性包含了当前应用中,非系统创建、管理的window,非系统创建管理的window比如有status bar,数组 windows
从前到后,依次是应用底层到顶层的window,所以数组 windows
最后一个元素一定是在应用的顶层。
而 windows
这个数组看似是一个栈的数据结构,所以是不是说我们每次拿该数组的lastObject就是拿到了顶层window呢?的确是的。然而在很多的情况下,我们有可能拿到了一个奇怪的window,也许是透明的,也许是0尺寸的,也许是可见的,这种情况可能是某些弹出视图导致的,可能性有很多。
有人说iOS应用中只有一个window,显然不是的:比如很多AlertView都是基于window实现的。
那么这就到了这个问题的背景:文首我提到的 XxxActionSheet.show()
方法中,我把这个actionSheet添加到了 UIApplication.sharedApplication().windows.last
上,在一个普通VC中,这样是没有问题的,因为当前的 keyWindow
就是 windows.last
,然后尝试在VC上展示某个第三方HUD,再调用 XxxActionSheet.show()
,我竟发现根本看不到这个actionSheet,然而它是在响应链上的——控件能够响应交互,这说明 XxxActionSheet
被添加到了一个不可见的window上。
所以,以后需要呈现在顶部的视图,要添加到 UIApplication.sharedApplication().keyWindow
上。
keyWindow
确保了你一定能拿到当前活跃的window,文档中是这样描述 keyWindow
的:
Discussion
This property holds the UIWindow object in the windows array that is most recently sent the makeKeyAndVisible message.
哦!如果你用代码写程序入口的话, makeKeyAndVisible
不正是在AppDelegate中对window做的设置吗。