获取rootViewController的正确方式

最近项目中经常会出现,不同的弹框同时出现在一个界面上的情况,所以研究了一下,如何避免此种情况的发生。

(关于UIAlertView显示的问题可参考:https://www.jianshu.com/p/7ac398ef4532)

首先,获取rootViewController的方式有两种:

    //方法一:
    UIWindow *windowW = [UIApplication sharedApplication].keyWindow;
    UIViewController *rootViewController1 = windowW.rootViewController;
    NSLog(@"rootViewController111 = %@",rootViewController1);

    //方法二:
    AppDelegate *appDele = (AppDelegate *)[UIApplication sharedApplication].delegate;
    UIViewController *rootViewController2 = appDele.window.rootViewController;
    NSLog(@"rootViewController222 = %@",rootViewController2);

这两种方法,一般情况下没有区别,但是有时候就会存在差异性,

keyWindow属性:

获取rootViewController的正确方式_第1张图片

UIAlertView的出现是因为,生成了一个新的window,加在了界面上面。这个时候获取到的keyWindow就是UIAlertControllerShimPresenterWindow。可以通过如下代码实验:

-(void)demo8{
    //获取rootViewController的两种方法,建议使用第二种
//    //方法一:
//    UIWindow *windowW = [UIApplication sharedApplication].keyWindow;
//    UIViewController *rootViewController1 = windowW.rootViewController;
//    NSLog(@"rootViewController111 = %@",rootViewController1);
//
//    //方法二:
//    AppDelegate *appDele = (AppDelegate *)[UIApplication sharedApplication].delegate;
//    UIViewController *rootViewController2 = appDele.window.rootViewController;
//    NSLog(@"rootViewController222 = %@",rootViewController2);
    
    UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    tempBtn.frame = CGRectMake(100, 100, 100, 100);
    [tempBtn setBackgroundColor:[UIColor cyanColor]];
    [tempBtn setTitle:@"输出结果" forState:UIControlStateNormal];
    [tempBtn addTarget:self action:@selector(tempBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:tempBtn];
    
}
-(void)tempBtnClick:(UIButton *)btn{
    if ([[[UIDevice currentDevice] systemVersion] floatValue]>=9.0) {
        UIAlertController *alertC = [UIAlertController alertControllerWithTitle:@"测试RootViewController" message:@"测试测试" preferredStyle:UIAlertControllerStyleAlert];
        UIAlertAction *cancelA = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];
        [alertC addAction:cancelA];
        [self presentViewController:alertC animated:YES completion:nil];
    }else{
        UIAlertView *alertV = [[UIAlertView alloc]initWithTitle:@"测试RootViewController" message:@"测试测试" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil, nil];
        [alertV show];
    }
    
    //方法一:
    UIWindow *windowW1 = [UIApplication sharedApplication].keyWindow;

    //方法二:
    AppDelegate *appDele = (AppDelegate *)[UIApplication sharedApplication].delegate;
    UIWindow *windowW2 = appDele.window;
    
    //从输出的结果可以看出,如果用以前的UIAlertView弹窗,两种方式输出的结果不一样,如果使用的UIAlertController弹窗,输出的结果一样,所以建议使用第二种方式进行rootViewController的获取
    NSLog(@"输出:\n 当前版本号为:%f \n window111 = %@   \n window222 = %@   \n window111.rootViewController = %@   \n window222.rootViewController = %@   \n",[[[UIDevice currentDevice] systemVersion] floatValue],windowW1,windowW2,windowW1.rootViewController,windowW2.rootViewController);
}

输出的结果:

输出:
 当前版本号为:11.200000 
 window111 = <_UIAlertControllerShimPresenterWindow: 0x7fbde44194e0; frame = (0 0; 375 667); opaque = NO; gestureRecognizers = ; layer = >   
 window222 = ; layer = >   
 window111.rootViewController =    
 window222.rootViewController = 

结果明显不一样,其实我们一般情况下想获取的rootViewController是第二种,希望我们获取到在appdelegate中设置的appdelaget.window.rootViewController。

所以了建议获取rootViewController的时候还是采用:

AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;

UIViewController *rootViewController1 = appdelegate.window.rootViewController;

其实,和alertView类似的,UIActionSheet也是这样的。有时候如果不获取到正确的rootViewController,可能就会出现重叠或者视图处理不正确的问题,建议:即时通过第二种方法获取到了RootViewController,在使用之前建议再判断一下获取到的类是不是就是自己想要的类型,更保险一些。

AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    if ([appdelegate.window.rootViewController isKindOfClass:["想要获取到的rootVC" class]] == YES) {
        
    }

你可能感兴趣的:(iOS开发等常用知识点,根视图,iOS,OC,uiwindow)