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

(关于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的正确方式_iOS

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 = <NSArray: 0x604000446570>; layer = <UIWindowLayer: 0x604000034de0>>
window222 = <UIWindow: 0x7fbde440b780; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x6040004417a0>; layer = <UIWindowLayer: 0x604000034860>>
window111.rootViewController = <UIApplicationRotationFollowingController: 0x7fbde44372f0>
window222.rootViewController = <UINavigationController: 0x7fbde4831a00>

结果明显不一样,其实我们一般情况下想获取的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) {

}