iOS开发笔记 | 看完这篇就不会再被keyWindow坑了
故事回放
我点击“兑换”按钮,弹出UIAlertView提示用户是否兑换商品,用户如果点击确定,则发送请求到后台,后台返回OK则兑换,这个时候前端显示自定义弹窗提示用户兑换成功,自定义弹窗是add在keyWindow上的view。
遇到的问题是:
有时这个提示兑换成功的自定义弹窗显示了一下就消失了但是有时又是正常的一直显示。
重现问题
我把这个问题简化了一下,先来看下下面的两段简单的代码:
代码一:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
// 创建一个alertView
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"因缺思厅" delegate:self cancelButtonTitle:@"取消" otherButtonTitles: nil];
[alertView show];
// 在keyWindow上add一个红色view
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(90, 90, 90, 90)];
redView.backgroundColor = [UIColor redColor];
[[UIApplication sharedApplication].keyWindow addSubview:redView];
}
代码二:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
// 在keyWindow上add一个红色view
UIView *redView = [[UIView alloc] initWithFrame:CGRectMake(90, 90, 90, 90)];
redView.backgroundColor = [UIColor redColor];
[[UIApplication sharedApplication].keyWindow addSubview:redView];
// 创建一个alertView
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"title" message:@"因缺思厅" delegate:self cancelButtonTitle:@"取消" otherButtonTitles: nil];
[alertView show];
}
代码一和代码二的区别只是其中的代码位置调整了一下。一个是先创建alertView,一个是先在keyWindow上添加redView。
现在的问题是:当点击alertView的取消按钮后上面两段代码会有什么不同的表现吗?
如果你不能一眼看出来,说明你现在还是年轻司机😏。
分别来张GIF回答此问题:
代码一 redView会消失.gif 代码二 redView不会消失
在代码一中,点击alertView的取消按钮后,alertView消失,紧接着红色view也消失。
为什么?redView明明是add到keyWindow上的,怎么跟着alertView消失了,难道alertView跟keyWindow有什么联系?😳
现在就来验证一下:
试着解决问题
不过验证之前我们先补充一下基础,先看一下官方文档对keyWindow
的解释。
什么你没网?😳 好吧Xcode里快捷键cmd+shift+0
打开离线文档。😏
官方文档里对keyWindow的解释是:
This property holds the UIWindow object in the windows array that is most recently sent the makeKeyAndVisible message.
我来翻译一下:最近一次发送 makeKeyAndVisible message的window。
对于makeKeyAndVisible这个方法我们肯定不陌生,毕竟AppDelegate.m每次都在写。但还是看一下官方文档对它的解释吧:
This is a convenience method to show the current window and position it in front of all other windows at the same level or lower. If you only want to show the window, change its hidden property to NO.
意思就是说用这个方法可以方便的将当前window放在所有window的最顶层(当然是相同level或者跟level更低的比较)。
如果能证明UIAlertView的window发送了makeKeyAndVisible消息就可以说明UIAlertView的window是keyWindow。那么怎么证明呢😳? 算了太麻烦了还是来点直接的吧😂
直接验证下面的代码:
if ([alertView.window isEqual:[UIApplication sharedApplication].keyWindow]) {
NSLog(@"alertView在keyWindow中");
}
还真的是。
也就是说在开篇的代码一中,redView add到keyWindow上时其实就是add到alertView的window上。
现在来回答遇到的那个问题
为什么有时这个提示兑换成功的自定义弹窗显示了一下就消失了但是有时又是正常的一直显示。
点击“确认兑换”按钮的时候,UIAlertView慢慢变透明,当完全透明的时候UIAlertView从父视图上移除(从不透明变透明并移除,这个过程大概一秒),UIAlertView移除后,它的window接着也释放(我是这样想到,不然内存泄漏对不对嘛),这个时候我们在请求数据,请求成功后展示“兑换成功”的自定义弹窗。如果这个时候UIAlertView还没有移除,那么这个自定义弹窗其实是add到UIAlertView的window上的,当UIAlertView完全变透明并移除的时候,UIAlertView的window释放,作为subView的自定义弹窗也就跟着一起移除了,这就是为什么有时自定义弹窗显示了一下就消失了的原因。如果网络不是很好,UIAlertView移除后才加载完数据展示自定义弹窗,这个时候自定义弹窗就会一直展示而不会突然消失了。
总结和反思
会遇到这个问题,可以说是一个巧合,但更说明了自己的基础不够扎实以及代码不够严谨。
- 基础不够扎实:遇到这个问题的时候我并没有顺利找到问题的原因所在,而是后面发到群里让小伙伴找到原因的,当时有两位老司机(锤神门徒和上午来报)一眼就看到问题所在。所以说,还需要更加努力的学习才行。
- 代码不够严谨:这件事让我对曾今封装的弹窗有了怀疑,所有弹窗都是加在keyWindow上的,但是我却忘了keyWindow是会变的。像遇到这种情况就很可能出问题。
还有就是,要多向老司机学习开车技术,有时候,老司机稍微指导下,我们就可以节省大量时间。
最重要的:多思考,多总结。