iOS:从头捋一遍VC的生命周期
一、介绍
UIViewController是iOS开发中的核心控件,没有它那基本上任何功能都无法实现,虽然系统已经做了所有控件的生命维护,但是,了解它的生命周期是如何管理还是非常有必要的。网上有很多教程,别人写的始终是别人的,自己动手实践一下,理解才能更深刻,本文就来捋一遍VC的生命周期。
二、思路
通过三个VC,第1个VC是storyBoard创建的,第2个VC是纯code创建的,第3个是xib创建的。分别称为BoardInitViewController、CodeInitViewController、XibInitViewController,这三个控制器采用导航模式进行交互,现在在VC中把所有跟初始化相关的方法都实现一下并做打印,如下:
BoardInitViewController:
// // BoardInitViewController.m // 声明周期 // // Created by 夏远全 on 2019/11/3. // Copyright © 2019 Beijing Huayue Education Technology Co., Ltd. All rights reserved. // #import "BoardInitViewController.h" #import "CodeInitViewController.h" @interface BoardInitViewController () @end @implementation BoardInitViewController +(void)load { [super load]; NSLog(@"boardVc---------%s",__func__); } +(void)initialize { [super initialize]; NSLog(@"boardVc---------%s",__func__); } +(instancetype)alloc { NSLog(@"boardVc---------%s",__func__); return [super alloc]; } - (nullable instancetype)initWithCoder:(NSCoder *)coder { NSLog(@"boardVc---------%s",__func__); return [super initWithCoder:coder]; } - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { NSLog(@"boardVc---------%s",__func__); return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; } -(instancetype)init { NSLog(@"boardVc---------%s",__func__); return [super init]; } - (void)loadView { [super loadView]; NSLog(@"boardVc---------%s",__func__); } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor greenColor]; self.title = @"boardVc"; NSLog(@"boardVc---------%s",__func__); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"boardVc---------%s",__func__); } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"boardVc---------%s",__func__); } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; NSLog(@"boardVc---------%s",__func__); } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"boardVc---------%s",__func__); } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; NSLog(@"boardVc---------%s",__func__); } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; NSLog(@"boardVc---------%s",__func__); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"boardVc---------%s",__func__); } -(void)dealloc { NSLog(@"boardVc---------%s",__func__); } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { CodeInitViewController *codeVc = [[CodeInitViewController alloc] init]; [self.navigationController pushViewController:codeVc animated:YES]; } @end
CodeInitViewController:
// // CodeInitViewController.m // 声明周期 // // Created by 夏远全 on 2019/11/3. // Copyright © 2019 Beijing Huayue Education Technology Co., Ltd. All rights reserved. // #import "CodeInitViewController.h" #import "XibInitViewController.h" @interface CodeInitViewController () @end @implementation CodeInitViewController +(void)load { [super load]; NSLog(@"codeVc---------%s",__func__); } +(void)initialize { [super initialize]; NSLog(@"codeVc---------%s",__func__); } +(instancetype)alloc { NSLog(@"codeVc---------%s",__func__); return [super alloc]; } - (nullable instancetype)initWithCoder:(NSCoder *)coder { NSLog(@"codeVc---------%s",__func__); return [super initWithCoder:coder]; } - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { NSLog(@"codeVc---------%s",__func__); return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; } -(instancetype)init { NSLog(@"codeVc---------%s",__func__); return [super init]; } - (void)loadView { [super loadView]; NSLog(@"codeVc---------%s",__func__); } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor greenColor]; self.title = @"codeVc"; NSLog(@"codeVc---------%s",__func__); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"codeVc---------%s",__func__); } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"codeVc---------%s",__func__); } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; NSLog(@"codeVc---------%s",__func__); } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"codeVc---------%s",__func__); } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; NSLog(@"codeVc---------%s",__func__); } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; NSLog(@"codeVc---------%s",__func__); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"codeVc---------%s",__func__); } -(void)dealloc { NSLog(@"codeVc---------%s",__func__); } -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //通过xib创建 XibInitViewController *xibVc = [[XibInitViewController alloc] init]; [self.navigationController pushViewController:xibVc animated:YES]; } @end
XibInitViewController:
// // XibInitViewController.m // 声明周期 // // Created by 夏远全 on 2019/11/3. // Copyright © 2019 Beijing Huayue Education Technology Co., Ltd. All rights reserved. // #import "XibInitViewController.h" @interface XibInitViewController () @end @implementation XibInitViewController +(void)load { [super load]; NSLog(@"xibVc---------%s",__func__); } +(void)initialize { [super initialize]; NSLog(@"xibVc---------%s",__func__); } +(instancetype)alloc { NSLog(@"xibVc---------%s",__func__); return [super alloc]; } - (nullable instancetype)initWithCoder:(NSCoder *)coder { NSLog(@"xibVc---------%s",__func__); return [super initWithCoder:coder]; } - (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil { NSLog(@"xibVc---------%s",__func__); return [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; } -(instancetype)init { NSLog(@"xibVc---------%s",__func__); return [super init]; } - (void)loadView { [super loadView]; NSLog(@"xibVc---------%s",__func__); } - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor blueColor]; self.title = @"xibVc"; NSLog(@"xibVc---------%s",__func__); } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"xibVc---------%s",__func__); } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"xibVc---------%s",__func__); } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; NSLog(@"xibVc---------%s",__func__); } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"xibVc---------%s",__func__); } - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; NSLog(@"xibVc---------%s",__func__); } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; NSLog(@"xibVc---------%s",__func__); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"xibVc---------%s",__func__); } -(void)dealloc { NSLog(@"xibVc---------%s",__func__); } @end
三、注解
+load: 程序启动后,在系统的main函数调用之前,系统就会加载所有的load方法,提前进行一些资源包的配置或者hook,(可以打断点看看结果,本人亲测过) +initialize: 当前类或者其子类未被初始化过时会首次调用,若以后当前类或者子类再多次初始化时不会再调用,一般提前为初始化做一些工作 +alloc: 系统为当前类分配内存时调用,在C语言中就是malloc这一步 -initWithCoder: 通过storyBoard方式实例化的vc,需要经过反序列化,这个方法会被调用 -initWithNibName:bundle: 通过xib文件或者init方法实例化的vc,这个方法都会被调用,其实init方法最终都会走该方法 -init: 通过纯代码实例化Vc会调用,其最终会调用initWithNibName:bundle:方法 -loadView: 实例化Vc后,可以加载一些系统常规的View -viewDidLoad: 一般加载自定义的view或者初始化属性,视图加载完毕后会调用 -viewWillAppear: 视图即将出现会调用 -viewWillDisappear: 视图即将消失会调用 -viewWillLayoutSubviews: 视图加载完毕后即将要布局 -viewDidLayoutSubviews: 视图加载完毕后布局也完成了 -didReceiveMemoryWarning: 加载视图时,内存消耗太大,出现内存警告,会调用 -dealloc: 实例化被销毁,进行内存的回收会调用
四、演示
[1] 程序启动,加载storyBoard实例化BoardInitViewController
2019-11-03 16:23:45.724860+0800 声明周期[6081:439250] codeVc---------+[CodeInitViewController load] 2019-11-03 16:23:45.725520+0800 声明周期[6081:439250] boardVc---------+[BoardInitViewController load] 2019-11-03 16:23:45.725713+0800 声明周期[6081:439250] xibVc---------+[XibInitViewController load] 2019-11-03 16:23:45.875841+0800 声明周期[6081:439250] boardVc---------+[BoardInitViewController initialize] 2019-11-03 16:23:45.876016+0800 声明周期[6081:439250] boardVc---------+[BoardInitViewController alloc] 2019-11-03 16:23:45.876132+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController initWithCoder:]
2019-11-03 16:23:45.932805+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController loadView] 2019-11-03 16:23:45.935257+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewDidLoad] 2019-11-03 16:23:45.935932+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewWillAppear:] 2019-11-03 16:23:45.938655+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewWillLayoutSubviews] 2019-11-03 16:23:45.938840+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewDidLayoutSubviews] 2019-11-03 16:23:45.960117+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewDidAppear:]
[2] 从BoardInitViewController中push到纯代码实例化的CodeInitViewController中
2019-11-03 16:26:21.027613+0800 声明周期[6081:439250] codeVc---------+[CodeInitViewController initialize] 2019-11-03 16:26:21.027858+0800 声明周期[6081:439250] codeVc---------+[CodeInitViewController alloc] 2019-11-03 16:26:21.027986+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController init] 2019-11-03 16:26:21.028089+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController initWithNibName:bundle:] 2019-11-03 16:26:21.032537+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController loadView] 2019-11-03 16:26:21.032821+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewDidLoad] 2019-11-03 16:26:21.032967+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewWillDisappear:] 2019-11-03 16:26:21.033095+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewWillAppear:] 2019-11-03 16:26:21.054149+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewWillLayoutSubviews] 2019-11-03 16:26:21.054325+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewDidLayoutSubviews] 2019-11-03 16:26:21.581912+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewDidDisappear:] 2019-11-03 16:26:21.582262+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewDidAppear:]
[3] 从CodeInitViewController中push到Xib实例化的XibInitViewController中
2019-11-03 17:03:12.506639+0800 声明周期[6437:478856] codeVc---------+[CodeInitViewController alloc] 2019-11-03 17:03:12.506831+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController init] 2019-11-03 17:03:12.507020+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController initWithNibName:bundle:] 2019-11-03 17:03:12.508456+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController loadView] 2019-11-03 17:03:12.509038+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController viewDidLoad] 2019-11-03 17:03:12.509353+0800 声明周期[6437:478856] boardVc----------[BoardInitViewController viewWillDisappear:] 2019-11-03 17:03:12.509780+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController viewWillAppear:] 2019-11-03 17:03:12.520785+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController viewWillLayoutSubviews] 2019-11-03 17:03:12.521002+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController viewDidLayoutSubviews] 2019-11-03 17:03:13.023817+0800 声明周期[6437:478856] boardVc----------[BoardInitViewController viewDidDisappear:] 2019-11-03 17:03:13.024016+0800 声明周期[6437:478856] codeVc----------[CodeInitViewController viewDidAppear:]
[4] 将XibInitViewController进行Pop后
2019-11-03 16:38:55.287065+0800 声明周期[6081:439250] xibVc----------[XibInitViewController viewWillDisappear:] 2019-11-03 16:38:55.287238+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewWillAppear:] 2019-11-03 16:38:55.803065+0800 声明周期[6081:439250] xibVc----------[XibInitViewController viewDidDisappear:] 2019-11-03 16:38:55.803504+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewDidAppear:] 2019-11-03 16:38:55.803857+0800 声明周期[6081:439250] xibVc----------[XibInitViewController dealloc]
[5] 将CodeInitViewController进行Pop后
2019-11-03 16:40:07.038091+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewWillDisappear:] 2019-11-03 16:40:07.038281+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewWillAppear:] 2019-11-03 16:40:07.543910+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController viewDidDisappear:] 2019-11-03 16:40:07.544089+0800 声明周期[6081:439250] boardVc----------[BoardInitViewController viewDidAppear:] 2019-11-03 16:40:07.544236+0800 声明周期[6081:439250] codeVc----------[CodeInitViewController dealloc]
四、总结
- 程序一启动,系统在当前应用程序的所有方法被调用之前优先加载load方法;
- 控制器生命的正常流程是:初始化--->加载视图--->将要显示---->布局子视图---->完全显示---->将要显示---->完全消失----->对象销毁(有可能内存警告释放)
- 控制器交互的前后显隐流程是交叉的,在源VC即将消失和目的VC即将显示之后,目的VC会完成所有子视图的布局,然后源VC才会真正消失目的VC真正显示
- 控制器交互消失的流程也是交叉的,目的VC即将消失,源VC即将显示,目的VC完全消失,源VC完全显示,接着释放目的VC
- 通过stroyBoard创建的VC一定需要反序列化
- 通过纯代码和xib创建的VC,最终都会调用initWithNibName:bundle:方法
程序猿神奇的手,每时每刻,这双手都在改变着世界的交互方式!