最近项目中经常会出现,不同的弹框同时出现在一个界面上的情况,所以研究了一下,如何避免此种情况的发生。
(关于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属性:
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) { }