iOS 坑的集中营iOS DeveloperIOS

创建的UIWindow为什么不显示

2016-10-14  本文已影响2205人  踩坑小分队

创建了一个window却不显示,怎么个情况。
相关代码如下:
创建一个按钮,通过按钮的单击事件来创建window,创建的window是不需要添加到相关的控件的,只要创建就会添加到界面上。
1、但是这里也创建window了,怎么没有显示?

- (void)test2
{
    UIWindow *myWindow3 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    myWindow3.backgroundColor = [UIColor greenColor];
    myWindow3.windowLevel = 100;
    myWindow3.hidden = NO;
    [myWindow3 makeKeyWindow];
    
    NSLog(@"1当前所有的window %@",[UIApplication sharedApplication].windows);
}

2、但是将window设置成员变量就能够如期的看到window,代码如下

@interface ViewController ()
@property(nonatomic,strong)UIWindow *myWindow1;
@end

通过按钮响应事件调用test1方法,会发现创建的window显示出来了

// 将window设置成全局变量
- (void)test1
{
    self.myWindow1 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.myWindow1.backgroundColor = [UIColor redColor];
    self.myWindow1.windowLevel = -1;
    self.myWindow1.hidden = NO;
}

也就是说window必须要设置成成员变量才能被显示出来吗?为什么?继续进行以下相关的测试:
3、没有声明成成员变量,单独创建的window类,直接调用没有显示

// 单独创建UIWindow类
- (void)test3
{
    MyWindow1 *myWindow = [[MyWindow1 alloc] initWithFrame:[UIScreen mainScreen].bounds];
    myWindow.backgroundColor = [UIColor greenColor];
    myWindow.windowLevel = 100;
    myWindow.hidden = NO;
    [myWindow makeKeyWindow];
}

4、单独创建UIWindow类,然后设置成全局变量,创建window之后有window显示

@interface ViewController ()
@property(nonatomic,strong)MyWindow1 *myWindow;
@end
- (void)test4
{
    self.myWindow = [[MyWindow1 alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.myWindow.backgroundColor = [UIColor greenColor];
    self.myWindow.windowLevel = 100;
    self.myWindow.hidden = NO;
    [self.myWindow makeKeyWindow];
}

5、创建单例window

+ (ShowWindow *)shareShowWindow
{
    static ShowWindow *window = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (window == nil) {
            window = [[ShowWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        }
    });
    
    return window;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor redColor];
        // 在window上面添加相关控件
        UIButton *tempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
        tempBtn.frame = CGRectMake(100, 200, 100, 100);
        [tempBtn setTitle:@"点我消失" forState:UIControlStateNormal];
        tempBtn.backgroundColor = [UIColor greenColor];
        [tempBtn addTarget:self action:@selector(clickBtn:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:tempBtn];
    }
    return self;
}

- (void)clickBtn:(UIButton *)sender
{
    self.hidden = YES;
}

- (void)show
{
    [self makeKeyWindow];
    self.hidden = NO;
}

在ViewController中调用,创建的window显示了

// 创建window的单例进行实验
- (void)test5
{
    ShowWindow *window = [ShowWindow shareShowWindow];
    [window show];
}

总结:通过以上的实验可以总结出,并不是只有成员变量才可以,单例也可以,他们的共同点就是生命周期足够长。
这个时候产生一个疑问,单独创建的一个局部变量的button,添加在view上面怎么能够显示?UIWindow的父类虽然也是UIView,但是UIWindow的显示方式和view不一样。一般的view创建完了是需要添加到父控件上面的,对,就是这个"添加",父控件强引用了button,也就是button的引用计数+1了。
刚刚上面也说了,"创建的window是不需要添加到相关的控件的,只要创建就会添加到界面上",window并没有添加到任何的地方。
那么创建完了window可以找到吗?当然可以。通过以下代码可以找到创建的window。

NSLog(@"2当前所有的window %@",[UIApplication sharedApplication].windows);

我测试的时候也是这么观察的

- (void)clickBtn:(UIButton *)sender
{
    // 为了观察是不是新创建的window被当前的window挡住了
    AppDelegate *app = (AppDelegate *)[UIApplication sharedApplication].delegate;
    app.window.alpha = 0.3;
    
    // 可以显示创建的window
    [self test1];
    
    // 不能正常显示创建的window
//    [self test2];
    
    // 不能正常的显示创建的window
//    [self test3];
    
    // 可以正常的显示创建的window
//    [self test4];
    
    // 可以正常显示创建的window
//    [self test5];
    
    NSLog(@"2当前所有的window %@",[UIApplication sharedApplication].windows);
}

在以上的实验中不同的方式添加window,添加完毕之后就可以查看windows中的情况了。
比如调用完了test1,打印[UIApplication sharedApplication].windows就会发现多一个window,并且可以和test1创建的window比较一下,确认是一个window。调用完test3,会发现没有添加新的window。
相关的Demo可以参考:https://github.com/RunOfTheSnail/UIWindowDemo

这是为什么?难道创建完了window没有被添加进[UIApplication sharedApplication].windows中吗?猜想,没有被添加进去,新创建的window没有被[UIApplication sharedApplication].windows强引用,很可能仅仅是弱引用。
做如下实验:
还是通过按钮的点击事件调用的。

// 测试创建的window和[UIApplication sharedApplication].windows的关系
- (void)test6
{
    self.myWindow2 = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.myWindow2.backgroundColor = [UIColor greenColor];
    self.myWindow2.windowLevel = 100;
    self.myWindow2.hidden = NO;
    [self.myWindow2 makeKeyWindow];
    NSLog(@"查看1   %@",[UIApplication sharedApplication].windows);
    self.myWindow2 = nil;
    NSLog(@"查看2   %@",[UIApplication sharedApplication].windows);
}

打印结果如下:这个和想要的结果不一样,想要的结果是第一次打印两个window,第二次打印一个window,有点演砸了。。。。。。。。

2016-10-14 10:06:57.459 UIWindowDemo[83896:1915917] 查看1   (
    "<UIWindow: 0x7fef83713620; frame = (0 0; 375 667); alpha = 0.3; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fef83714b40>; layer = <UIWindowLayer: 0x7fef83710f80>>",
    "<UIWindow: 0x7fef85010e30; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7fef850122a0>; layer = <UIWindowLayer: 0x7fef85010570>>"
)
2016-10-14 10:06:57.460 UIWindowDemo[83896:1915917] 查看2   (
    "<UIWindow: 0x7fef83713620; frame = (0 0; 375 667); alpha = 0.3; autoresize = W+H; gestureRecognizers = <NSArray: 0x7fef83714b40>; layer = <UIWindowLayer: 0x7fef83710f80>>",
    "<UIWindow: 0x7fef85010e30; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7fef850122a0>; layer = <UIWindowLayer: 0x7fef85010570>>"
)

但是得考虑一个问题。短时间window可能会不释放的问题,进行再一次的实验
创建另外一个测试按钮,通过点击事件来查看windows中的情况

 // 这个是配合着test6来测试的,查看windows数组的情况
    UIButton *myTempBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [myTempBtn setTitle:@"再点我,测试test2" forState:UIControlStateNormal];
    myTempBtn.frame = CGRectMake(100, 300, 300, 100);
    myTempBtn.backgroundColor = [UIColor greenColor];
    [myTempBtn addTarget:self action:@selector(clickMyTempBtn:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:myTempBtn];
- (void)clickMyTempBtn:(UIButton *)sender
{
    NSLog(@"查看3 %@",[UIApplication sharedApplication].windows);
}
 查看3 (
    "<UIWindow: 0x7faa09439ec0; frame = (0 0; 375 667); alpha = 0.3; autoresize = W+H; gestureRecognizers = <NSArray: 0x7faa0943af80>; layer = <UIWindowLayer: 0x7faa094369e0>>"

运行完test6之后,查看1和查看2打印的结果都是两个window,点击测试按钮之后,再次测试发现打印的是一个window,这下放心了。验证了自己的猜想。

总结:
1、创建的window不需要添加到任何的控件上就能显示,显示的规律是通过windowLevel的等级来显示的,相关参考:http://www.jianshu.com/p/f60471a7d935
2、新创建的window没有被[UIApplication sharedApplication].windows强引用,只是能通过[UIApplication sharedApplication].windows找到创建的window。所以想要创建的window显示,那就必须保证其生命周期。

以上是我自己根据相关的运行效果总结的,如果有哪位大神觉得有地方描述的不准确,欢迎指正哈,在下感激不尽!!!

上一篇下一篇

猜你喜欢

热点阅读