iOS 关于UIAlertController、UIAlertV

作者: 小白进城 | 来源:发表于2017-10-23 10:27 被阅读1384次

    关于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

    原因分析:

    一个视图控制器仅能使用presentViewController模态方法弹出一个控制器

    如果想在模态方法弹出第二个视图控制器,可以使用已弹出的alert1来弹出


    扩展

    使用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);
    

    结果:

    结果

    上图可知:

    1、在UIAlertView没有使用show之前,delegate.window和keyWindow内存地址是一致的,表示当前的keyWindow就是我们应用的window,一般情况下,两者是同一个

    2、在UIAlertView使用show之后,keyWindow发生了变化,已经被系统替换为新的window,这个新的window用来展示UIAlertView;但是此时delegate.window还是原来的那个

    结论:

    虽然UIAlertView可以解决同时弹出两个弹窗的问题,但是UIAlertView的实现机制会改变keyWindow

    如果使用keyWindow的获取应用控制器的时候,最好将keyWindow改成delegate.window,因为keyWindow是会变动的


    扩展:验证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);
    

    结果:

    结果

    结论:

    1、使用UIAlertController并不会改变keyWindow

    2、不能弹出两个控制器




    综上所述:

    1、弹窗两个以上的时候,使用UIAlertView

    2、使用keyWindow的地方,最好改为delegate.window,这两者还是有些不同的
    3、模态方式跳转视图时,self只能展现一个控制器,若是需要展现第二个,需要当前已经展现的控制器继续模态方式跳转

    相关文章

      网友评论

        本文标题:iOS 关于UIAlertController、UIAlertV

        本文链接:https://www.haomeiwen.com/subject/invouxtx.html