iOS-[UIApplication sharedApplication].keyWindow为nil的分析

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

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

果然是刚刚说的原因, 也就是系统在调用 [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上的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值