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的生命周期的更多相关文章

  1. iOS view和viewController的生命周期

    一.ViewController的职责 对内管理与之关联的View,对外跟其他ViewController通信和协调.对于与之关联的View,ViewController总是在需要的时候才加载视图,并 ...

  2. ViewController的生命周期分析和使用

    iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...

  3. ViewController的生命周期

    # ViewController 的生命周期 # ViewController的生命周期中各个方法的流程如下: init loadView :加载view viewDidLoad :view加载完毕 ...

  4. Unity 3D Framework Designing(3)——构建View和ViewModel的生命周期

    > 对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者 ...

  5. Unity应用架构设计(3)——构建View和ViewModel的生命周期

    对于一个View而言,本质上是一个MonoBehaviour.它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等.这些是非常好的方法,可以让开发者在各个阶段 ...

  6. iOS viewController 和 view 的创建消失生命周期总结

    控制器创建的生命周期 1. 如果从stroryBoard 中产生一个controller,那么会先调用initWithCoder:, awakeFromNib, loadView,viewDidLoa ...

  7. iOS - ViewController的生命周期

    iOS SDK中提供很多原生的ViewController,大大提高了我们的开发效率:那么下面我们就根据开发中我们常用的ViewController谈一谈它的生命周期: (一)按照结构和用法可以对iO ...

  8. [zhang] ViewController的生命周期分析和使用

    iOS的SDK中提供很多原生ViewController,大大提高了我们的开发效率,下面是我的一些经验. 一.结构 按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的 ...

  9. ios ViewController的生命周期分析和基本使用逻辑

    按结构可以对iOS的所有ViewController分成两类:1.主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UITable ...

随机推荐

  1. 计算机与ARM板通过路由器相连

    首先,使用两根网线分别将计算机和ARM板与路由器的LAN口连接. 要想使计算机和ARM板通信,必须使二者在同一网段. 在计算机的终端输入:ifconfig 获取计算机的ip地址,查看eth0,我的ip ...

  2. 从头开始——重装ubuntu

    一.装系统 环境:计算机原本装的系统是windows7+ubuntu 14.04,后来ubuntu的启动项被我手贱破坏了,进不了ubuntu,只能重新安装. 启动盘:使用UltraISO软碟通制作U ...

  3. 关于mysql binlog日志的格式说明

    Binary Log 记录方式 Row Level Binary Log会记录成每一行数据被修改的形式,然后在Slave端再对相同的数据进行修改. 如果修改了表的结构,那么binlog日志记录的是重新 ...

  4. Android多媒体开发-- OpenMax IL简介

    1.openmax 简介 http://www.khronos.org/openmax/ OpenMax是一个多媒体应用程序的框架标准,由NVIDIA公司和Khronos在2006年推出. OpenM ...

  5. C - Big Number

    Description In many applications very large integers numbers are required. Some of these application ...

  6. VS C4819 编译错误解决方法

    偶尔用别人的代码,出现: warning C4819: The file contains a character that cannot be represented ). Save the fil ...

  7. Java三大特征之继承(二)

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  8. 为什么我们需要性能测试,需要loadrunner

    什么是功能: 功能按我理解就是软件实现需求,提供服务,那么功能测试就是实现的需求是否与客户给定需求一致,也就是符合预期结果 什么是性能: 功能是实现需求,提供服务,那么性能就可以理解为服务的好坏.比如 ...

  9. ruby和Python简单对比

    前不久学了ruby,发现ruby和Python非常像,于是自个测试对比了下,测完了才知道网上有现成的……下面是测试结果   序列(包括列表和元组等)有分片的特点:可能会比较方便的提取其中特定元素,暂时 ...

  10. 使用Java管理Azure(1):基础配置

    Azure针对Java开发人员提供了非常丰富的开发库,开发工具,和相关插件,让你通过Java对Azure进行服务管理和开发,本文第一步先介绍如何快速的配置Java开发工具,主要针对目前比较流行的Ecl ...