UIView和UIViewController一样,也有自己的生命周期。
UIView包含的常见方法如下:
- (void)didAddSubview:(UIView *)subview;
- (void)willRemoveSubview:(UIView *)subview;
- (void)willMoveToSuperview:(nullable UIView *)newSuperview;
- (void)didMoveToSuperview;
- (void)willMoveToWindow:(nullable UIWindow *)newWindow;
- (void)didMoveToWindow;
另外添加了View常见的构造函数,析构函数,等,如下,一起分析(仅做简单分析,以上面六个为主):
- (instancetype)init;
- (void)dealloc;
- (void)removeFromSuperview;
- (void)drawRect:(CGRect)rect;
- (void)layoutSubviews;
搭建测试工程,工程简单框架如下:
PS:ViewController是第一个VC,中间有一个按钮。SecoundViewController是第二个视图,中间有一个测试视图,即TestView对象。还有俩按钮,分别是移除TestView(TestView.removeFromSupperView),和重置TestView的Frame。
在测试类中依次打印上述几个方法,代码如下(顺序不对,但不影响结果):
#import "TestView.h"
@implementation TestView{
NSInteger _count;
}
- (instancetype)init{
if (self = [super init]) {
_count = 0;
NSLog(@"%@", [NSString stringWithFormat:@"%@ ==> %ld",NSStringFromSelector(_cmd),_count]);
}
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)didAddSubview:(UIView *)subview{
[super didAddSubview:subview];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)willRemoveSubview:(UIView *)subview{
[super willRemoveSubview:subview]; _count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)willMoveToSuperview:(nullable UIView *)newSuperview{
[super willMoveToSuperview:newSuperview];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)drawRect:(CGRect)rect{
[super drawRect:rect];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)didMoveToSuperview{ [super didMoveToSuperview];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)willMoveToWindow:(nullable UIWindow *)newWindow{
[super willMoveToWindow:newWindow];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)didMoveToWindow{
[super didMoveToWindow];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)removeFromSuperview{
[super removeFromSuperview];
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
- (void)dealloc{
_count++;
NSLog(@"%@ ==> %ld",NSStringFromSelector(_cmd),_count);
}
@end
经过测试发现,如果是简单的push过去,remove掉view,log日志如下:
因为testView没有subView,所以didAddSubview和willRemoveSubview都不会调用,这个在后面单独说。
仔细查看,会发现和superView,window相关的方法,都调了两次。打开官方开发文档,描述如下
四个方法都是类似的描述,大意是说这个view得父类变化时,无论是添加还是移除,都是调用will和did两个方法,这也就是上文为啥都打印了两次的原因。一次是add,一次是remove。带参数的will方法中,参数不为空是添加,为空时移除。
PS:比较有意思的是window,官方介绍是Tells the view that its window object is about to change.意思是说,这个view他自己的window对象,将要发生变化。意思是说,这个view有个window对象,和我之前理解不同。关于UIView,UIWindow,CALayer之间的关系,其他篇目中再介绍。
2.然后与系统打印出来的VC的生命周期作对照,我的简单理解如下:
view添加到父视图,移除父视图,调用的是superview相关的。view真正在屏幕上显示出来/移除掉,是和UIWindow相关的。
3.为testView添加了一个subView,在testView的生命周期中,会调用didAddSubview和willRemoveSubview,这俩方法也是成对出现的。log如下
UIView是在被加到俯视图上之后,才会寻找添加自己的子视图。
UIView是在dealloc之后,才开始removeSubView。
1.UIView生命周期加载阶段。在loadView阶段(内存加载阶段),先是把自己本身都加到superView上面,再去寻找自己的subView并依次添加。到此为止,只和addSubview操作有关,和是否显示无关。等到所有的subView都在内存层面加载完成了,会调用一次viewWillAppear,然后会把加载好的一层层view,分别绘制到window上面。然后layoutSubview,DrawRect,加载即完成。
2.UIView生命周期移除阶段。会先依次移除本view的moveToWindow,然后依次移除所有子视图,掉他们的moveToWindow,view就在window上消失不见了,然后在removeFromSuperView,然后dealloc,dealloc之后再removeSubview。(但不理解为什么dealloc之后再removeSubview)
3.如果没有子视图,则不会接收到didAddSubview和willRemoveSubview消息。
4.和superView,window相关的方法,可以通过参数(superView/window)或者self.superView/self.window,判断是创建还是销毁,如果指针不为空,是创建,如果为空,就是销毁。这四个方法,在整个view的生命周期中,都会被调用2次,一共是8次。
5.removeFromSuperview和dealloc在view的生命周期中,调且只调用一次,可以用来removeObserver,移除计时器等操作。(layoutSubview可能会因为子视图的调整,多次调用)
6.UIView是在被加到自己的父视图上之后,才开始会寻找添加自己的子视图(数据层面的添加,并不是加到window上面)。UIView是在调用dealloc中,移除自己的子视图,所有子视图移除并销毁内存之后,才会销毁自己的内存,dealloc完成。
能力有限,难免有误,欢迎指正。
本文GitHub 点此下载