View和viewController的生命周期
View和viewController的生命周期
一、ViewController的职责
对内管理与之关联的View,对外跟其他ViewController通信和协调。对于与之关联的View,ViewController总是在需要的时候才加载视图,并在不需要的时候卸载视图,所以也同时担当了管理应用资源的责任
二、ViewController的生命周期
View是指Controller的View。它作为Controler的属性,生命周期在Controller的生命周期内。就是说你的Controller不能在view释放前就释放了。
viewController的生命周期图

需要说明的是:当你alloc并init了一个ViewController时,这个ViewController应该是还没有创建view的。ViewController的view是使用了lazyInit方式创建,就是说你调用的view属性的getter:[self view]。在getter里会先判断view是否创建,如果没有创建,那么会调用loadView来创建view。loadView完成时会继续调用viewDidLoad。loadView和viewDidLoad的一个区别就是:loadView时还没有view。而viewDidLoad时view以及创建好了。
三、view的加载过程
文字说明在表述流程的时候总是很费力的,我又找到了如下的两张图
view加载过程图

跟随如下文字理解viewController对view加载过程:
1 先判断子类是否重写了loadView,如果有直接调用。之后调viewDidLoad完成View的加载。
2 如果是外部通过调用initWithNibName:bundle指定nib文件名的话,ViewController记载此nib来创建View。
3 如果initWithNibName:bundle的name参数为nil,则ViewController会通过以下两个步骤找到与其关联的nib。
A 如果类名包含Controller,例如ViewController的类名是MyViewController,则查找是否存在MyView.nib;
B 找跟ViewController类名一样的文件,例如MyViewController,则查找是否存在MyViewController.nib。
4 如果子类没有重写的loadView,则ViewController会从StroyBoards中找或者调用其默认的loadView,默认的loadView返回一个空白的UIView对象。
注意第一步,ViewController是判断子类是否重写了loadView,而不是判断调用子类的loadView之后ViewController的View是否为空。就是说,如果子类重写了loadView的话,不管子类在loadView里面能否获取到View,ViewController都会直接调viewDidLoad完成View的加载。
view卸载过程图

跟随以下文字理解卸载过程:
1 系统发出警告或者ViewController本身调用导致didReceiveMemoryWarning被调用
2 调用viewWillUnload之后释放View
3 调用viewDidUnload
四、模拟器的调用顺序
我构架了这样一个环境,在该环境中有两个viewController,姑且命名为A和B,tag分别为1和2,A控制程序启动的时候即加载的界面,在A中放一个按钮,按下后会通过segue来调用到界面B;B 中页放一个按钮,通过执行
[self dismissModalViewControllerAnimated:YES];
来返回界面A
然后检测所有的函数调用,依次如下
加载A的时候依次调用
1 initWithCoder
1 loadView //如果说你进行了重写,会在这里调用,这一步可以参考下文
1 viewDidLoad
1 viewWillAppear
1 viewWillLayoutSubviews
1 viewDidLayoutSubviews
1 viewDidAppear
切换至B的时候依次调用
2 initWithCoder //先将2初始化
1 prepareForSegue //调用1的准备过度的函数,所以在该函数中可以对界面B的一些相关属性进行赋值
2 loadView //如果这里进行了重写
2 viewDidLoad //2界面加载
1 viewWillDisappear
2 viewWillAppear
2 viewWillLayoutSubviews
2 viewDidLayoutSubviews
2 viewDidAppear
1 viewDidDisappear
从B切换回A的时候依次调用
2 viewWillDisappear
1 viewWillAppear
1 viewDidAppear
2 viewDidDisappear
2 dealloc
顺序总结下来加载依次为:加载 - 显示 - 布局
完成顺序依次为:完成布局 - 完成显示 - 完成加载
小注:-(void)loadView;函数如果重写,下面是一个可能的demo
-(void)loadView
{
CGRect applicationFrame = [[UIScreenmainScreen] applicationFrame];
UIView *contentView = [[UIViewalloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColordarkGrayColor];
self.view = contentView;
UILabel *lab = [[UILabelalloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
lab.text = @"HelloWorld";
[self.viewaddSubview:lab];
}
loadView虽然返回值为空,但必须在函数体内对self.view进行赋值,否则会在建立该界面的时候收到如下的log信息:
Application windows are expected to have a root view controller at the end of application launch
具体执行顺序为:代码执行了initWithCoder之后直接调用了三次loadView函数,并且没有调用其它函数(包括viewDidLoad 、viewWillDisappear、viewWillLayoutSubviews)
疑问:
暂不清楚为什么会调用三次,我的猜测是:上述三个函数分别检测了一遍view是否存在,发现不存在,所以各自调用了一遍viewLoad,最后发现依然不存在,所以上述三个函数分别返回了失败,加载完成
但矛盾的地方是:为什么上述三个函数本身没有执行到?底层到底做了什么?
五、view和ViewController的创建阶段,关于什么时候应该干什么
1、init
Allocating critical data structures required by your view controller
不要出现创建view的代码。良好的设计,在init里应该只有相关数据的初始化,而且这些数据都是比较关键的数据。init里不要掉self.view,否则会导致viewcontroller创建view。(因为view是lazyinit的)。
2、loadView
Creating your view objects
只初始化view,一般用于创建比较关键的view如tableViewController的tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super loadView前),最好也不要初始化一些非关键的view。如果你是从nib文件中创建的viewController在这里一定要首先调用super的loadView方法,但建议不要重载这个方法。
3、viewDidLoad
Allocating or loading data to be displayed in your view
这时候view已经有了,最适合创建一些附加的view和控件了。有一点需要注意的是,viewDidLoad会调用多次(viewcontroller可能多次载入view,参见图2)。
4、viewWillAppear 这个一般在view被添加到superview之前,切换动画之前调用。在这里可以进行一些显示前的处理。比如键盘弹出,一些特殊的过程动画(比如状态条和navigationbar颜色)。
5、viewDidAppear 一般用于显示后,在切换动画后,如果有需要的操作,可以在这里加入相关代码。
6、viewDidUnload
Releasing references to view objects
Releasing data that is not needed when your view is not displayed
这时候viewController的view已经是nil了。由于这一般发生在内存警告时,所以在这里你应该将那些不在显示的view释放了。比如你在viewcontroller的view上加了一个label,而且这个label是viewcontroller的属性,那么你要把这个属性设置成nil,以免占用不必要的内存,而这个label在viewDidLoad时会重新创建。
7、dealloc
Releasing critical data structures required by your view controller
六、几点备注:
1、按结构可以对iOS的所有ViewController分成两类:
1)、主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITableViewController,UIViewController。
2)、用于控制和显示其他ViewController的ViewController。这种ViewController一般都是一个ViewController的容器。如UINavigationController,UITabbarController。它们都有一个属性:viewControllers。其中UINavigationController表示一种Stack式结构,push一个ViewController或pop一次,因此后一个ViewController一般会依赖前一个ViewController。而UITabbarController表示一个Array结构,各个ViewController是并列的。
第一种ViewController会经常被继承,用来显示不同的数据给用户。而第二种很少被继承,除非你真的需要自定义它。
2、当view被添加其他view中之前时,会调用viewWillAppear,而之后会调用viewDidAppear。
当view从其他view中移出之前时,会调用viewWillDisAppear,而之后会调用viewDidDisappear。
当view不在使用,而且是disappeared,受到内存警告时,那么viewController会将view释放并将其指向nil。
3、由于Controller加载View时,会自动将一些View对象指向其对应的IBOutlet变量。
所以当view被卸载时我们必须在viewDidUnload将这些变量release掉,ViewController不会自动做这件事。
具体做法是将变量设置为空,(注意和dealloc中将变量release的区别)注意此时Controller的view属性是空的。
事例
- (void)viewDidLoad
{
NSLog(@"加载之后");
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)viewDidAppear:(BOOL)animated
{
NSLog(@"动画qian");
}
-(void)viewDidDisappear:(BOOL)animated
{
NSLog(@"动画后");
}
- (void)viewDidUnload
{
NSLog(@"加载之后");
[superviewDidUnload];
// Release any retained subviews of the main view.
}
-(void)viewWillAppear:(BOOL)animated
{
NSLog(@"显示之前");
}
-(void)viewWillDisappear:(BOOL)animated
{
NSLog(@"显示之hou");
}
View和viewController的生命周期的更多相关文章
- iOS view和viewController的生命周期
一.ViewController的职责 对内管理与之关联的View,对外跟其他ViewController通信和协调.对于与之关联的View,ViewController总是在需要的时候才加载视图,并 ...
- ViewController的生命周期分析和使用
iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...
- ViewController的生命周期
# ViewController 的生命周期 # ViewController的生命周期中各个方法的流程如下: init loadView :加载view viewDidLoad :view加载完毕 ...
- Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期
> 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...
- Unity应用架构设计(3)——构建View和ViewModel的生命周期
对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...
- iOS viewController 和 view 的创建消失生命周期总结
控制器创建的生命周期 1. 如果从stroryBoard 中产生一个controller,那么会先调用initWithCoder:, awakeFromNib, loadView,viewDidLoa ...
- iOS - ViewController的生命周期
iOS SDK中提供很多原生的ViewController,大大提高了我们的开发效率:那么下面我们就根据开发中我们常用的ViewController谈一谈它的生命周期: (一)按照结构和用法可以对iO ...
- [zhang] ViewController的生命周期分析和使用
iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...
- ios ViewController的生命周期分析和基本使用逻辑
按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITable ...
随机推荐
- 那些 Cynthia 教我的事 之 PMSec (二)
一.在Foreach之前要判断是否为空. 常常从数据库里取出来表就直接用了,很少记得判断是否有值.不严谨的说. 专业人员写的是酱滴... DataLayer.PMSecDataSet.PMSECReq ...
- php zendstudio 常用的一些自定义模板标签
<?php /** * xxx.php * ============================================== * Copy right 2013-2016 http: ...
- 网易云数据结构- Maximum Subsequence Sum
题目 题目地址 思路 显然是最大子列和的进化版,那就先思考下经典的最大子列和.这也是道思维题,啥算法也没用到,全是思维技巧,真心不知道考试遇到这种题该怎么办了. 存放答案的一个类,我把它看成一个袋子, ...
- delphi access中SQL根据时间查询
Access数据库虽然功能是差了点,但是有时对一些少量的数据保存很是很方便的,在delphi中也是如此,在查询时免不了要按照日期或 时间作为查询条件,access有些特别. select * from ...
- Redis与Scrapy
Redis与Scrapy Redis与Scrapy Redis is an open source, BSD licensed, advanced key-value cache and store. ...
- ORA-04092: COMMIT 不能在触发器中
触发器无需commit也不能写commit触发器和触发它的DML是同一个事务DML提交了,触发器的操作也提交了,要不就一起回滚了 当然,如果你一定要在触发器里写COMMIT那就用自治事务相当于一个事务 ...
- MySQL5.7新特性笔记
001.用户验证方式上的变化 MySQL5.7已经不要支持mysql_old_password验证插件,也不再支持old_password函数,也就说old_passwords也就不能被设置成1了.
- ES5 object的新函数
虽然说现在并不是所有的浏览器都已经支持ECMAScript5的新特性,但相比于ECMAScript4而言ECMAScript5被广大浏览器厂商广泛接受,目前主流的浏览器中只有低版本的IE不支持,其它都 ...
- 32位程序调用Oracle11gR2数据库libclntsh.so失败
[问题描述]32位程序调用Oracle11gR2数据库的libclntsh.so库时会返回失败. [问题原因]32位程序只能调用32位的Oracle客户端实例包,而R2数据库默认安装完毕后是没有lib ...
- HP-UX磁带备份错误收集
磁带备份命令: make_tape_recovery -Av 默认备份至/dev/rmt/0mn. 如果有多个磁带机,那么需要使用下面命令 make_tape_recovery -Av -a /de ...