iOS使用[UIApplication sharedApplication].keyWindow添加子视图的问题
开发的时候我们经常遇到这样的场景,就是在当前视图界面上添加一个黑色透明的蒙版。一般我们就是新建一个蒙版view,然后加在当前显示的window上。如下:
1-1代码
uiwindow *window = [uiapplication sharedapplication].keywindow;//注:keywindow当前显示界面的window uiview *subview = [[cview alloc] initwithframe:[uiscreen mainscreen].bounds]; subview.backgroundcolor = [uicolor blackcolor]; subview.alpha = 0.5; [window addsubview:subview];
一般我们就是在keywindow上直接添加这种蒙版的view,小编也不例外。但今天确遇到了一个诡异的问题,就是由于使用这个keywindow造成的。
下面简单交代下问题背景:
项目中有这样的场景,就是点击某一按钮之后,会优先弹出一个的uialertview的弹框,然后会在alertview的点击代理的回调
- (void)alertview:(uialertview *)alertview clickedbuttonatindex:(nsinteger)buttonindex
里面调用显示蒙版的方法(方法的实现和上面1-1代码类似)。然后就出现了奇怪的问题,我添加在keywindow上的蒙版加上去之后瞬间消失了。
分析问题:
1.看到蒙版自己消失了第一反应想到应该会走自定义蒙版view的dealloc方法,于是就在dealloc方法那打了一个断点。
2.果然走到我们的蒙版view dealloc方法被调用了,但我又没有自己掉dimiss和remvoe方法,怎么会dealloc的。
3.分析调用dealloc之前的方法栈,
发现window调用了dealloc,因为我们蒙版的父视图keywindow dealloc释放掉了,所以我们的蒙版就消失了
4.解释了蒙版的消失,但当前的window怎么dealloc呢?我的界面明明还正常显示呢。
5.猜测是不能当前显示蒙版的keywindow和我们显示主界面的keywindow不一样导致的,但为啥会不一致呢,之前这样把蒙版直接加在keywindow上都没关系,难道和在alertview回调显示有关系。
6.做了上面大胆的假设,开始一步步调试,
//a.在alertveiw弹框弹出之前打印keywindow的值 (lldb) po [uiapplication sharedapplication].keywindow ; layer = >
//b.在alertview的代理方法- (void)alertview:(uialertview *)alertview clickedbuttonatindex:(nsinteger)buttonindex里打印keywindow的值 po [uiapplication sharedapplication].keywindow <_uialertcontrollershimpresenterwindow: 0x7fa48c613ad0; frame = (0 0; 414 736); opaque = no; autoresize = w+h; gesturerecog
//c.在alertview的代理方法- (void)alertview:(uialertview *)alertview diddismisswithbuttonindex:(nsinteger)buttonindex alertview消失之后再打印 (lldb) po [uiapplication sharedapplication].keywindow ; layer = >通过上面的打印,我们可以清楚的看到。在alertview弹出之后的keywindow和我们弹出之前消失之后的keywindow是不一样的。地址和对象都不同一个
uiwindow: 0x7fa48c611c00 和 _uialertcontrollershimpresenterwindow: 0x7fa48c613ad0
这就解释了为啥我们弹出的视图出现后就消失了,因为当alertveiw弹出的时候的当前的keywidow已经是_uialertcontrollershimpresenterwindow对象了,alertview消失之后,这个window就释放了,所以加在上面的蒙版就消失了。
解决方法:
1.我们看到在uialertview另一个回调里- (void)alertview:(uialertview *)alertview diddismisswithbuttonindex:(nsinteger)buttonindex uialertview dismiss之后的keywindow和我们是一样的,可以在这里使用[uiapplication sharedapplication].keywindow方式去加视图。
2.不适用[uiapplication sharedapplication].keywindow这种方式,[[uiapplication sharedapplication] delegate].window 或
[[uiapplication sharedapplication].windows objectatindex:0]这两种方式,这样获取的window不是当前的keywindow,而是主window。
总结分析:
1.使用uialertview的时候,无论是自己写还是封装给别人使用的时候,最好都
- (void)alertview:(uialertview *)alertview diddismisswithbuttonindex:(nsinteger)buttonindex 这个回调,因为这是alertview已经完全消失。
2.我们不可避免的会遇到问题,我们平常习以为常的东西,有些场景也会遇到一些特殊的问题,我们要保持警惕。
3.遇到问题,才能更好的提升,多做总结。
推荐阅读
-
iOS14适配【 采用hook全局性地解决UITableViewCell兼容问题】往cell添加子视图的方式不规范,导致contentView 置于自定义控件的上层,引发界面无响应(注意处理相关方法)
-
iOS使用[UIApplication sharedApplication].keyWindow添加子视图的问题
-
iOS使用[UIApplication sharedApplication].keyWindow添加子视图的问题
-
iOS14适配【 采用hook全局性地解决UITableViewCell兼容问题】往cell添加子视图的方式不规范,导致contentView 置于自定义控件的上层,引发界面无响应(注意处理相关方法)