UIViewController是IOS中顶层视图的载体和控制器,用户与程序界面的交互都是由UIViewController来控制的,UIViewController管理UIView的生命周期及资源的加载与释放。
我们创建一个简单的demo来测试一下其生命周期,新建两个ViewController,一个是A页面,一个是B页面。A页面有个按钮可以跳转到B页面,并且在每个ViewController的每个方法中都添加了NSLog来打印其状态。截取AViewController.m部分代码如下,
#pragma mark -- 生命周期test---(instancetype)init{ if(self = [super init]){ self.title = @"A页面"; } NSLog(@"init :%@",self.title); return self; } -(void ) loadView{ [super loadView]; NSLog(@"LoadView :%@",self.title); } -(void)viewDidLoad { [super viewDidLoad]; NSLog(@"viewDidLoad :%@",self.title); [self setupUI]; } -(void) viewWillAppear:(BOOL)animated{ [ super viewWillAppear:animated]; NSLog(@"viewWillAppear :%@",self.title); } -(void) viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; NSLog(@"viewDidAppear :%@",self.title); } -(void) viewWillDisappear:(BOOL)animated{ [super viewWillDisappear:animated]; NSLog(@"viewWillDisappear :%@",self.title); } -(void) viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; NSLog(@"viewDidDisappear :%@",self.title); } -(void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"didReceiveMemoryWarning :%@",self); } -(void) dealloc{ NSLog(@"dealloc: %@",self.title); }
然后开始运行测试
case 1:第一次启动APP
点击开始按钮后,进入A页面,如下图
这时打印出的信息如下
分析:
可见,执行的方法如下
1、(alloc)init
分配地址并初始化ViewController对象
2、loadView
每个ViewController都会有一个view的属性,是一个UIView类型。loadView方法就是用于加载这个这个view,通常这一步不需要去干涉,父类已经实现好了,如果要重写这个方法,要么调用父类的该方法,要么自定义一个UIView对象并赋值给当前ViewController的view属性。这个view相当于一个画布,其他的自定义控件一般都是添加到它上面的。
3、viewDidLoad
顾名思义,也就是上面说到的view加载完了就会调用这个方法,一些自定义控件的代码可以在这里写。
4、viewWillAppear
视图将要显示在屏幕前调用 。
5、viewDidAppear
视图已经在屏幕渲染完成后调用。
case 2:点击按钮,从A页面push到B页面
如下图所示
控制台打印信息为
分析:
1、B页面 init
2、B页面 loadView
3、B页面 viewDidLoad
4、A页面 viewWillDisappeare
前三点在#case 1#已经分析过了就不分析了。第4点viewWillDisappeare,是在A页面即将要消失在屏幕时调用,一个新的页面出现总会有个旧的页面消失
5、B页面 viewWillAppear
6、A页面 viewDidDisappear
在页面已经消失在屏幕后调用。
7、viewDidAppear
case 3:点击左上角的返回,关闭B页面,并返回A页面
控制台打印信息如下
分析:
前四个方法在上面已经分析过了,就不累赘了,第五个方法是dealloc,是在视图销毁时执行,因为从B页面返回到A页面后,B页面已经不需要了(在A页面永远不知道下一个切换的页面是哪里),和#case 2#不同的是,因为从A页面push到B页面,A页面还是有存在的价值的(因为还需要返回到A页面,如果销毁了A就没办法返回了),所以A页面是没有调用dealloc方法的。在这个方法里面一般是做一些释放内存的操作。
case 4:当从A页面push到B页面后,模拟内存不足,控制台打印信息如下
分析:
由打印信息可知,当内存不足时就会触发didReceiveMemoryWarning 方法,每个viewController的此方法都会被调用。
总结:
由上面的的例子可知,一个页面要被创建就会经过一下几步
step 1:(alloc)init
step 2: loadView
step 3: viewDidView
step 4: viewWillAppear
step 5: viewDidAppear
一个页面要被移除,会经过如下几步
step 1: viewWillDisappear
step 2: viewDidDisappear
step 3:dealloc (如果不再需要这个页面了才执行)
下图是对上面分析的总结
扩展:
1、当在AViewController.m的 init、 loadView、 viewDidView或viewWillAppear的方法里面添加sleep(5)语句时,会发现启动APP后要等大概5秒左右才能显示出A页面,可见,如果出现页面加载缓慢等问题,有可能是在这几个方法中耗时操作过多。
2、当在AViewController.m中的viewDidAppear方法中加入sleep(5)语句,会发现,虽然A页面已经渲染完成了,但是里面的控件却无法操作,比如按钮点击无响应。可见,一些页面卡顿,响应迟钝等问题可能是在这个方法中耗时操作过多。
基本的生命周期大概如此,如有错误或需要补充说明,欢迎指正