最近一个app在使用monkey的过程中发现点击一段时间以后,无法响应触摸事件。经定位原因是UIAlertView出现后,直接使用dismissviewcontroller进行dismiss,就会导致这种情况,主要是因为UIAlertView dismiss以后,会生成一个_UIAlertControllerShimPresenterWindow覆盖在屏幕上方,导致无法响应触摸事件。
ps:苹果在iOS8.0后推出了UIAlertController以代替UIAlertView,导致的后果就是UIAlertView在iOS9.0之后被deprecated了,但是一些老的app仍然会使用UIAlertView进行弹窗。
接下来再看一看_UIAlertControllerShimPresenterWindow是个什么,UIWindow 的继承关系如下图所示:
_UIAlertControllerShimPresenterWindow 这个系统AlertView的载体window 不在[UIApplication sharedApplication].windows 数组中,这也导致了当时定位这个问题是非常困难的。
那么UIAlertView是怎么实现的呢?主要是如下三步:
1、当 UIAlertView alloc init 的时候,只是创建了一个 UIAlertView 实例,它并没有被添加到父 view 上。
2、当调用 [AlertView show] 的时候,系统创建一个新的 UIWindow 实例_UIAlertControllerShimPresenterWindow,设为当前 application 的 keyWindow,并保存原有的 keyWindow 指针,然后把 alertView 添加到这个新建的 keyWindow 上,此时 alertView 就显示在设备屏幕上了。
3、当 alertView 需要消失的时候,系统调用dismiss方法,然后再设置 application 的 keyWindow 为之前保存的 window,再设置 _UIAlertControllerShimPresenterWindow.hide = YES 来销毁 _UIAlertControllerShimPresenterWindow。
通过以上分析我们知道在调用dismiss方法使alertView消失以后,需要设置_UIAlertControllerShimPresenterWindow.hide = YES 来销毁_UIAlertControllerShimPresenterWindow,并设置原来的window为keyWindow
代码如下:
if([NSStringFromClass([[UIApplication sharedApplication].keyWindow class]) isEqual:@"_UIAlertControllerShimPresenterWindow"]){
[[UIApplication sharedApplication].keyWindow setHidden:YES] ;
}
[[[[UIApplication sharedApplication] delegate] window] makeKeyWindow] ;
参考文章
1、https://note.leodev.me/2015/12/29/iOS-How-to-implement-the-UIAlertView-of-the-system/
2、https://www.jianshu.com/p/d9b7d53749fd