创建了一个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 (
"; layer = >",
"; layer = >"
)
2016-10-14 10:06:57.460 UIWindowDemo[83896:1915917] 查看2 (
"; layer = >",
"; layer = >"
)
但是得考虑一个问题。短时间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 (
"; layer = >"
运行完test6之后,查看1和查看2打印的结果都是两个window,点击测试按钮之后,再次测试发现打印的是一个window,这下放心了。验证了自己的猜想。
总结:
1、创建的window不需要添加到任何的控件上就能显示,显示的规律是通过windowLevel的等级来显示的,相关参考:http://www.jianshu.com/p/f60471a7d935
2、新创建的window没有被[UIApplication sharedApplication].windows强引用,只是能通过[UIApplication sharedApplication].windows找到创建的window。所以想要创建的window显示,那就必须保证其生命周期。
以上是我自己根据相关的运行效果总结的,如果有哪位大神觉得有地方描述的不准确,欢迎指正哈,在下感激不尽!!!