iOS [UIApplication sharedApplica

作者: 大风先生bigWind | 来源:发表于2017-08-30 17:25 被阅读1934次

    1. 概述

    本人最近在写一个自定义弹框(去看看), 在不停的跑demo过程中, 发现怎么也无法将弹窗显示出来, 然后打断点进行调试, 发现[UIApplication sharedApplication].keyWindow竟然为nil:

    image.png

    然后各种找原因, 大概原因就是在用[UIApplication sharedApplication].keyWindow获取keywindow的时候, keywindow并没有被创建, 需要在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中设置window并makeKeyAndVisible; 我按照这个来做了, 还是不行!!!!

    于是继续找, 有的说是iOS7.0会有[UIApplication sharedApplication].keyWindow获取不到keywindow的情况, iOS8.0就好多了, 这种情况下可以用[[[UIApplication sharedApplication] delegate] window];代替, 然后试着这样做了, 结果还是现实不出来, 点击调试视图看到我要的弹窗竟然被window盖住了, 有图有真相:

    image.png

    2. 原因分析

    前面看了网上一些分析, 其实有时候并不是十分适合自己的情况, 但也能提供很多思路的指导, 本人自己的分析原因大概是这样的:

    最主要的原因是本人将创建和弹出弹窗的代码放在了viewWillAppear方法里面, 为什么这样是不行的呢, 咱们具体代码具体分析, 首先先看AppDelegate.m里面的代码是这样的

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        
        RSViewController *VC = [[RSViewController alloc] init];   
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.window.rootViewController = VC;    
        [self.window makeKeyAndVisible];   
        return YES;
    }
    

    这里已经设置了makeKeyAndVisible, 所以说上面说的对应的问题应该是不存在了;

    接下来看看创建弹窗的代码, 是在RSViewController.m文件里的:

    - (void)viewWillAppear:(BOOL)animated{
    
        [super viewWillAppear:animated];
        
        /*
         登录的弹框
         d*/
        RSAlertView *alerV = [[RSAlertView alloc] initIfLogin];
        alerV.registerBlock = ^{
            
            NSLog(@"注册的block");
        };
        alerV.loginBlock = ^(){
            
            NSLog(@"登录的block");
        };
        [alerV showRSAlertView];
    
    }
    

    看到这里还是看不出问题是吧, 那我们可以试着验证一下是不是"通过[UIApplication sharedApplication].keyWindow获取keywindow的时候没有创建keywindow并makeKeyAndVisible", 为了便于标注, 我就上截图吧, 在箭头的地方分别加上几个BSLog

    image.png

    还有这里

    image.png

    然后将项目跑起来, 打印出来的结果是这样的:

    image.png

    注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!注意看顺序!!!

    果然是刚刚说的原因, 也就是系统在调用 [UIApplication sharedApplication].keyWindow之后才makeKeyAndVisible!!!!!!

    知道原因在哪了吧!!!!!!

    所以为了能继续顺利测试, 我们必须要在makeKeyAndVisible之后才使用[UIApplication sharedApplication].keyWindow, 要正确的判断之前还是之后, 就涉及到老生常谈的生命周期了, 这个这里就不赘述了, 要不然又是讲半天, 这里就说怎么弄吧:
    很简单, 创建弹框的方法不要放在viewWillAppear也不要放在viewWillAppear或者- (void)viewDidLayoutSubviews方法里, 可以放在

    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
    

    这样你就可以方便的进行测试了.

    注意 :到了这里, 其实使用[UIApplication sharedApplication].keyWindow或者[[[UIApplication sharedApplication] delegate] window]都是可以实现效果的; 但还是比较推荐后者, 因为使用前者的话, 当你的app需要跳转到别的app然后返回本app的时候, 有可能会导致UI错乱, 使用后者就不会.

    3. 疑惑

    虽然上面说了不放在生命周期的方法里面, 但小伙伴们肯定会马上机智的想到一个问题"那我使用的时候难道keywindow就能保证不是nil吗?", 这问题问得好.

    但其实大家不必担心, 因为一般项目里面, 弹窗的出现都是需要触发的, 例如服务器返回错误, 或者点击某个按钮的时候才会触发, 这时候是不会出现上面的问题的, 所以小伙伴们可以放心使用.

    另外, 我们也会想[UIApplication sharedApplication].keyWindow获取到的keywindow跟[[[UIApplication sharedApplication] delegate] window]获取到的有什么不同吗?
    这里大家可以看看另外的作者的分析
    stackoverflow上的

    相关文章

      网友评论

      • 被帅醒的小吴同志:两个window的level不同,你可以看看系统window的level等级就知道了
      • docManer:我们的项目有时候也会遇到这种奇怪的问题,测试人员把APP放在桌面,第二天来打开点击一些按钮没有反应,后来才发现视图是出来的,但是不在当前的windows上
        大风先生bigWind:@docManer 嗯,所以PO一下看看

      本文标题:iOS [UIApplication sharedApplica

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