关于UIAlertController弹窗问题
目标:同时弹出2个以上的弹窗
问题:在弹出一个alertController的时候,第二个alertController是无法弹出的
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"弹窗1" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *skipAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alertController addAction:cancelAction];
[alertController addAction:skipAction];
[self presentViewController:alertController animated:YES completion:nil];
UIAlertController *alertController2 = [UIAlertController alertControllerWithTitle:@"提示" message:@"弹窗2" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *skipAction2 = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alertController2 addAction:cancelAction2];
[alertController2 addAction:skipAction2];
[self presentViewController:alertController2 animated:YES completion:nil];
报错:
xcode给出的理由是:试图呈现已经呈现在self上的alert2
原因分析:
扩展
使用present,弹出普通的控制器
UIViewController *ctrl1 = [UIViewController new];
ctrl1.view.backgroundColor = [UIColor redColor];
[self presentViewController:ctrl1 animated:YES completion:nil];
UIViewController *ctrl2 = [UIViewController new];
ctrl2.view.backgroundColor = [UIColor yellowColor];
[self presentViewController:ctrl2 animated:YES completion:nil];
NSLog(@"self->%p",self);
NSLog(@"111->%p",ctrl1);
NSLog(@"222->%p",ctrl2);
结果:系统依旧不能present弹出两个视图,想弹出第二个视图的话,需要将self换成ctrl1;由于UIAlertController是继承自UIViewController的,UIViewController既然不能present弹出两个视图控制器,UIAlertController自然也不行
view is not in the window hierarchy!:视图不在窗口层次结构中
关于UIAlertView弹窗问题
目标:弹出两个提示窗体
UIAlertView *alertView1 = [[UIAlertView alloc] initWithTitle:@"提示" message:@"弹窗1" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
UIAlertView *alertView2 = [[UIAlertView alloc] initWithTitle:@"提示" message:@"弹窗2" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
[alertView1 show];
[alertView2 show];
测试结果:是可以弹出两个视图的,会展现最新弹窗,点击消失后,继续弹出之前的弹窗
似乎使用UIAlertView就可以满足弹出两个窗体的需求,但是新的问题随之而来
新问题的产生
在弹出UIAlertView窗体时,如果接下来使用到了[UIApplication sharedApplication].keyWindow.rootViewController来获取控制器等相关操作时,会出现闪退问题
原因:使用UIAlertView的show时,系统使用了一个新的Window来展现UIAlertView,所以当show弹窗时,keyWindow已经被替换
验证:我们来输出keyWindow的内存地址
// 弹窗之前window的内存地址
UIWindow *delegateWindow = [UIApplication sharedApplication].delegate.window;
UIWindow *keyWindow_pre = [UIApplication sharedApplication].keyWindow;
NSLog(@"delegateWindow->%p",delegateWindow);
NSLog(@"keyWindow_pre->%p",keyWindow_pre);
UIAlertView *alertView1 = [[UIAlertView alloc] initWithTitle:@"提示" message:@"弹窗1" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
UIAlertView *alertView2 = [[UIAlertView alloc] initWithTitle:@"提示" message:@"弹窗2" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
[alertView1 show];
[alertView2 show];
// 弹窗之后window的内存地址
UIWindow *delegateWindow_now = [UIApplication sharedApplication].delegate.window;
UIWindow *keyWindow_now = [UIApplication sharedApplication].keyWindow;
NSLog(@"delegateWindow_now->%p",delegateWindow_now);
NSLog(@"keyWindow_now->%p",keyWindow_now);
结果:
上图可知:
结论:
扩展:验证UIAlertController的keyWindow
验证:将弹窗换成UIAlertController,其他不变
// 弹窗之前window的内存地址
UIWindow *delegateWindow = [UIApplication sharedApplication].delegate.window;
UIWindow *keyWindow_pre = [UIApplication sharedApplication].keyWindow;
NSLog(@"delegateWindow->%p",delegateWindow);
NSLog(@"keyWindow_pre->%p",keyWindow_pre);
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"提示" message:@"弹窗1" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *skipAction = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alertController addAction:cancelAction];
[alertController addAction:skipAction];
[self presentViewController:alertController animated:YES completion:nil];
UIAlertController *alertController2 = [UIAlertController alertControllerWithTitle:@"提示" message:@"弹窗2" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *cancelAction2 = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *skipAction2 = [UIAlertAction actionWithTitle:@"ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alertController2 addAction:cancelAction2];
[alertController2 addAction:skipAction2];
[self presentViewController:alertController2 animated:YES completion:nil];
// 弹窗之后window的内存地址
UIWindow *delegateWindow_now = [UIApplication sharedApplication].delegate.window;
UIWindow *keyWindow_now = [UIApplication sharedApplication].keyWindow;
NSLog(@"delegateWindow_now->%p",delegateWindow_now);
NSLog(@"keyWindow_now->%p",keyWindow_now);
结果:
结论:
综上所述: