iOS 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属性是空的。
iOS view和viewController的生命周期的更多相关文章
- View和viewController的生命周期
View和viewController的生命周期 一.ViewController的职责 对内管理与之关联的View,对外跟其他ViewController通信和协调.对于与之关联的View,View ...
- ViewController的生命周期分析和使用
iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...
- iOS开发UI篇—UITabBarController生命周期(使用storyoard搭建)
iOS开发UI篇—UITabBarController生命周期(使用storyoard搭建) 一.UITabBarController在storyoard中得搭建 1.新建一个项目,把storyb ...
- ViewController的生命周期
# ViewController 的生命周期 # ViewController的生命周期中各个方法的流程如下: init loadView :加载view viewDidLoad :view加载完毕 ...
- Cordova - 使用Cordova开发iOS应用实战2(生命周期、使用Safari调试)
Cordova - 使用Cordova开发iOS应用实战2(生命周期.使用Safari调试) 前文我们创建了一个简单的Cordova项目,结构如下: 1,Cordova生命周期事件 (1)device ...
- [转] IOS中AppDelegate中的生命周期事件的调用条件
IOS中AppDelegate中的生命周期事件的调用条件 //当应用程序将要进入非活动状态执行,在此期间,应用程序不接受消息或事件,比如来电 - (void)applicationWillResign ...
- 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 ...
随机推荐
- java:高速排序算法与冒泡排序算法
Java:高速排序算法与冒泡算法 首先看下,冒泡排序算法与高速排序算法的效率: 例如以下的是main方法: /** * * @Description: * @author:cuiyaon ...
- Tomcat剖析(二):一个简单的Servlet服务器
Tomcat剖析(二):一个简单的Servlet服务器 1. Tomcat剖析(一):一个简单的Web服务器 2. Tomcat剖析(二):一个简单的Servlet服务器 3. Tomcat剖析(三) ...
- MVC使用百度开源文本编辑器UEditor实现图文并茂,字数限制,上传图片或涂鸦
原文:MVC使用百度开源文本编辑器UEditor实现图文并茂,字数限制,上传图片或涂鸦 文本编辑器有很多,比如ticymce和CKEditor就比较好用,但涉及到图片.文件上传,需要结合CKFinde ...
- vSphere HA状况:未知配置错误解决的方法
问题:vSphere HA配置出现未知错误,导致打不开主机上的虚拟机电源,vmware client连接vcenter后,主机显示警报信息,例如以下: 解决:例如以下图,选中有问题的物理主机,然后又一 ...
- linux 编译java并打包
一.首先是编译简单java文件(不引用外部jar包)如test.java public class test(){ System.out.println("hello world!" ...
- PHP实例——输出安全的HTML代码
原文:PHP实例--输出安全的HTML代码 //输出安全的htmlfunction h($text, $tags = null){ $text = trim($text); //完全过滤注释 $tex ...
- C++并发编程学习笔记<1> 入门
入门 多线程C++程序是什么样子的? 它看上去和其它全部C++程序一样,一般是变量.类以及函数的组合. 唯一真正的差别在于某些函数能够并发执行, 当然.为了并发地执行函数,必须使用特定的函数以及对象来 ...
- ORACLE 中IN和EXISTS比较
ORACLE 中IN和EXISTS比较 EXISTS的执行流程 select * from t1 where exists ( select null from t2 where y = x ...
- 对象javascript
//对象 var lennon=Object(); lennon.name="John"; lennon.year=1940; lennon.living=false; conso ...
- C# Winform 界面线程的Invoke死锁,以及Application.DoEvent的问题
1.对于非界面线程来说,Invoke是把一个操作丢到界面线程的队列里,然后阻塞,等到这个操作被界面线程完成后,才继续后续操作.也就是说,Invoke是同步的. 问题来了,如果界面线程此时正在等待这个非 ...