iOS对UIViewController生命周期和属性方法的解析
目录[-]
- iOS对UIViewController生命周期和属性方法的解析
 - 一、引言
 - 二、UIViewController的生命周期
 - 三、从storyBoard加载UIViewController实例的传值陷阱
 - 四、UIViewController与StroyBoard的相关相互方法
 - 1、ViewController直接在StoryBoard中进行跳转的传值
 - 2、使用代码跳转Storyboard中的controller
 - 五、UIViewController之间的一些从属关系
 - 1、parentViewController
 - 2、模态跳转中Controller的从属
 - 六、UIViewController的模态跳转及动画特效
 
iOS对UIViewController生命周期和属性方法的解析
一、引言
作为MVC设计模式中的C,Controller一直扮演着项目开发中最重要的角色,它是视图和数据的桥梁,通过它的管理,将数据有条有理的展示在我们的View层上。iOS中的UIViewController是UIKit框架中最基本的一个类。从第一个UI视图到复杂完整项目,都离不开UIViewController作为基础。基于UIViewController的封装和扩展,也能够出色的完成各种复杂界面逻辑。这篇博客,旨在讨论UIViewController的生命周期和属性方法,在最基础的东西上,往往会得到意想不到的惊喜。
二、UIViewController的生命周期
要了解UIViewController,先要弄清楚其生命周期。在面向对象的语言中,是对象,就一定要有生命周期,UIViewController也不例外,生命周期管理Controller的作用范围和时间,也管理其内对象的作用范围和时间。首先,UIViewController中与其生命周期有关的几个函数如下:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
 | 
//类的初始化方法+ (void)initialize;//对象初始化方法- (instancetype)init;//从归档初始化- (instancetype)initWithCoder:(NSCoder *)coder;//加载视图-(void)loadView;//将要加载视图- (void)viewDidLoad;//将要布局子视图-(void)viewWillLayoutSubviews;//已经布局子视图-(void)viewDidLayoutSubviews;//内存警告- (void)didReceiveMemoryWarning;//已经展示-(void)viewDidAppear:(BOOL)animated;//将要展示-(void)viewWillAppear:(BOOL)animated;//将要消失-(void)viewWillDisappear:(BOOL)animated;//已经消失-(void)viewDidDisappear:(BOOL)animated;//被释放-(void)dealloc; | 
上面这么多的函数,乍一看什么复杂,其实关系什么明朗,除了initialize,init和initWithCoder不是存在所有对象的声明周期中,其他函数都会在UIViewController的声明周期中有序的被调用。那么具体的调用顺序是怎样的呢,最好的办法是实践一下,通过编号打印,结果如下:

这是一个ViewController完整的声明周期,其实里面还有好多地方需要我们注意一下:
1:initialize函数并不会每次创建对象都调用,只有在这个类第一次创建对象时才会调用,做一些类的准备工作,再次创建这个类的对象,initalize方法将不会被调用,对于这个类的子类,如果实现了initialize方法,在这个子类第一次创建对象时会调用自己的initalize方法,之后不会调用,如果没有实现,那么它的父类将替它再次调用一下自己的initialize方法,以后创建也都不会再调用。因此,如果我们有一些和这个相关的全局变量,可以在这里进行初始化。
2:init方法和initCoder方法相似,只是被调用的环境不一样,如果用代码进行初始化,会调用init,从nib文件或者归档进行初始化,会调用initCoder。
3:loadView方法是开始加载视图的起始方法,除非手动调用,否则在ViewController的生命周期中没特殊情况只会被调用一次。
4:viewDidLoad方法是我们最常用的方法的,类中成员对象和变量的初始化我们都会放在这个方法中,在类创建后,无论视图的展现或消失,这个方法也是只会在将要布局时调用一次。
5:viewWillAppear:视图将要展现时会调用。
6:viewWillLayoutSubviews:在viewWillAppear后调用,将要对子视图进行布局。
7:viewDidLayoutSubviews:已经布局完成子视图。
8:viewDidAppare:视图完成显示时调用。
9:viewWillDisappear:视图将要消失时调用。
10:viewDidDisappear:视图已经消失时调用。
11:dealloc:controller被释放时调用。
注意:经过测试,从nib文件加载的controller,只要不释放,在每次viewWillAppare时都会调用layoutSubviews方法,有时甚至会在viewDidAppare后在调用一次layoutSubviews,而重点是从代码加载的则只会在开始调用一次,之后都不会,所以注意,在layoutSubviews中写相关的布局代码十分危险。
三、从storyBoard加载UIViewController实例的传值陷阱
我们知道,当我们从StoryBoard中加载ViewController时,我们在Controller中拖拽的视图是可以被初始化的,这里面有一点需要我们注意,如果我们需要向controller中视图进行传值设置,通过以下方法得到的Controller中,视图还没有被初始化创建出来:
| 
 1 
 | 
 ViewController2 * viewController2 = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"ViewController2"]; | 
我们可以在ViewController2的storyBoard中拉一个label,然后关联到头文件中,如下打印,会发现我们得到controller时,里面的视图对象并没有进行创建:
| 
 1 
2 
3 
 | 
ViewController2 * viewController2 = [[UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"ViewController2"];    NSLog(@"%@",viewController2.label);    [self presentViewController:viewController2 animated:YES completion:nil]; | 
打印如下:

可以想象,如果我们这时候需要对label进行一些属性设置,必然失败。有人提出可以在创建后,手动调以下loadView方法,我们试一下,结果如下:

可以看到,手动调用loadView后,label是被创建了出来,但是暴漏了一个更严重的问题,系统不在调用ViewDidLoad方法,这是十分有风险的,因为我们大部分的初始化代码都会放在这个方法里,所以手动调用loadView是一种错误的方法,apple文档声明对于loadView方法,我们从来都不要手动直接调用,那么我们如何实现创建后对成员对象进行传值设置呢,iOS9中增加了这样一个方法:
| 
 1 
 | 
- (void)loadViewIfNeeded NS_AVAILABLE_IOS(9_0); | 
这个方法十分有用,调用这个方法,会将视图创建出来,并且不会忽略viewDidLoad的调用。
在iOS9中,UIViewController还增加了下面一个布尔值的属性,可以同来判断controller的view是否已经加载完成:
| 
 1 
 | 
@property(nullable, nonatomic, readonly, strong) UIView *viewIfLoaded NS_AVAILABLE_IOS(9_0); | 
四、UIViewController与StroyBoard的相关相互方法
对于ViewConroller,我们一般有两种方式创建,一种是用纯代码的方式,一种是与StoryBoard关联,在UIViewController中,有许多方法方便我们与StoryBoard进行交互联系。
1、ViewController直接在StoryBoard中进行跳转的传值
在StoryBoard中进行界面跳转是十分方便的,我们在StoryBoard中拉入两个ViewController,在一个上面添加一个按钮,点住按钮按住control,将鼠标拉到第二个controller上,会出现如下的跳转选项:

我们选择一个后,就会在两个controller之间建立一个跳转连接。当我们运行点击按钮后,会自动从第一个controller跳转到第二个controller。在UIViewController中有如下方法可以对是否跳转进行控制:
| 
 1 
 | 
- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender NS_AVAILABLE_IOS(6_0); | 
这个方法如果返回NO,自动跳转将不能进行,会被拒绝,需要注意的是,这个方法只会在自动的跳转时被调用,我们手动使用代码跳转StoryBoard中的连接关系时是不会被调用的,我们后面讨论。
在执行过上述方法后,如果返回YES,系统还会在执行如下一个方法,作为跳转前的准备,我们可以在这个方法中进行一些传值操作,这个方法无论使我们手动进行跳转还是storyboard中自动跳转,都会被执行:
| 
 1 
 | 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(nullable id)sender NS_AVAILABLE_IOS(5_0); | 
sugur对象中封装了相关的ViewController,可以使用segue.destinationViewController获取。
segue在StoryBoard中除了用来自动正向跳转外,我们还可以进行反向的跳转,类似pop和dismiss方法,这种segue被称为unwind sugue。例如,我们有一个controller1和一个controllert2,要使用unwind segue从2返回1,我们需要在2中实现如下格式的方法:
| 
 1 
2 
3 
 | 
- (IBAction)unwindSegueToViewController:(UIStoryboardSegue *)segue {    NSLog(@"unwindSegueToViewController");} | 
这个方法中的返回值必须为IBAction,参数必须是UIStoryboardSegue,方法名我们可以自己定义,之后在StoryBoard中的ViewController1中的Exit选项中,我们会发现多了一个这样的方法:

我们可以把它连接到viewController2中的一个按钮上:

这样,当我们点击viewController2中的按钮时,就会返回到我们第一个ViewController1中了。
当然,在使用unwind segue方法时,也是会有一些回调帮助我们进行跳转前的设置和传值,UIViewController如下方法会在跳转前调用,返回NO,则不能进行跳转:
| 
 1 
2 
3 
4 
 | 
-(BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender{    NSLog(@"canPerformUnwindSegueAction");    return YES;} | 
之后会执行我们自定义的unwindSegue方法,这个方法中我们可以什么都不写,模式是会进行跳转的。
2、使用代码跳转Storyboard中的controller
我们除了在Storyboard中拉拉扯扯可以进行控制器的跳转外,我们也可以使用代码来跳转Storyboard中segue连接关系。
在Storyboard中两个控制器间建立一个segue联系,我们可以取一个名字:

在触发跳转的方法中,使用如下方法进行跳转,这里面的参数id就是我们取得segue的id:
| 
 1 
 | 
- (void)performSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender NS_AVAILABLE_IOS(5_0); | 
下面三个属性我们可以获取controller的nib文件名,其storyBoard和其Bundle:
| 
 1 
2 
3 
 | 
@property(nullable, nonatomic, readonly, copy) NSString *nibName;  @property(nullable, nonatomic, readonly, strong) NSBundle *nibBundle; @property(nullable, nonatomic, readonly, strong) UIStoryboard *storyboard NS_AVAILABLE_IOS(5_0); | 
五、UIViewController之间的一些从属关系
这部分的内容和方法可能我们接触用到的并不多,但是在某些情况下,使用这些方法可以大大的方便某些逻辑。
1、parentViewController
UIViewController里面封装了一个数组,可以存放其子ViewController,系统中使用的例子就是导航和tabBar这类的控制器,我们使用如下方法可以直接访问这些父的controller:
| 
 1 
 | 
@property(nullable,nonatomic,weak,readonly) UIViewController *parentViewController; | 
2、模态跳转中Controller的从属
在我们进行控制器的跳转时,只要控制器没有被释放,我们都可以顺藤摸瓜的找到它,使用如下两个方法:
| 
 1 
2 
3 
4 
 | 
//其所present的contller,比如,A和B两个controller,A跳转到B,那么A的presentedViewController就是B@property(nullable, nonatomic,readonly) UIViewController *presentedViewController  NS_AVAILABLE_IOS(5_0);//和上面的方法刚好相反,比如,A和B两个controller,A跳转到B,那么B的presentingViewController就是A@property(nullable, nonatomic,readonly) UIViewController *presentingViewController NS_AVAILABLE_IOS(5_0); | 
了解了上面方法我们可以知道,对于反向传值这样的问题,我们根本不需要代理,block,通知等这样的复杂手段,只需要获取跳转到它的Controller,直接设置即可。举个例子,我们需要在第二个界面消失后,改变第一个界面的颜色,在第二个controller中只需要下面的代码即可实现 :
| 
 1 
2 
 | 
    self.presentingViewController.view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1];    [self dismissViewControllerAnimated:YES completion:nil]; | 
六、UIViewController的模态跳转及动画特效
单纯的UIViewController中,我们使用最多的是如下的两个方法,一个向前跳转,一个向后返回:
| 
 1 
2 
 | 
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated: (BOOL)flag completion:(void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0);- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion NS_AVAILABLE_IOS(5_0); | 
从方法中,我们可以看到,有animated这个参数,来选择是否有动画特效,默认的动画特效是像抽屉一样从手机屏幕的下方向上弹起,当然,这个效果我们可以进行设置,UIViewController有如下一个属性来设置动画特效:
| 
 1 
 | 
@property(nonatomic,assign) UIModalTransitionStyle modalTransitionStyle NS_AVAILABLE_IOS(3_0); | 
注意,这个要设置的是将要跳转到的controller,枚举如下:
| 
 1 
2 
3 
4 
5 
6 
 | 
typedef NS_ENUM(NSInteger, UIModalTransitionStyle) {    UIModalTransitionStyleCoverVertical = 0,//默认的,从下向上覆盖    UIModalTransitionStyleFlipHorizontal ,//水平翻转    UIModalTransitionStyleCrossDissolve,//溶解    UIModalTransitionStylePartialCurl ,从下向上翻页}; | 
除了跳转的效果,还有一个属性可以设置弹出的controler的填充效果,但是这个属性只在pad上有效,在iphone上无效,都是填充到整个屏幕:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
11 
12 
13 
 | 
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle NS_AVAILABLE_IOS(3_2);//枚举如下typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {        UIModalPresentationFullScreen = 0,//填充整个屏幕        UIModalPresentationPageSheet,//留下状态栏        UIModalPresentationFormSheet,//四周留下变暗的空白        UIModalPresentationCurrentContext ,//和跳转到它的控制器保持一致        UIModalPresentationCustom NS_ENUM_AVAILABLE_IOS(7_0),//自定义        UIModalPresentationOverFullScreen NS_ENUM_AVAILABLE_IOS(8_0),        UIModalPresentationOverCurrentContext NS_ENUM_AVAILABLE_IOS(8_0),        UIModalPresentationPopover NS_ENUM_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED,        UIModalPresentationNone NS_ENUM_AVAILABLE_IOS(7_0) = -1,         }; | 
iOS对UIViewController生命周期和属性方法的解析的更多相关文章
- 【iOS开发】iOS对UIViewController生命周期和属性方法的解析
		
iOS对UIViewController生命周期和属性方法的解析 一.引言 作为MVC设计模式中的C,Controller一直扮演着项目开发中最重要的角色,它是视图和数据的桥梁,通过它的管理,将数据有 ...
 - 【iOS】UIViewController生命周期
		
UIViewController有2周期: 在UIViewController中,View存在两个循环:载入循环和卸载循环. 载入循环 1>程序请求controller的view. 2>假 ...
 - initWithFrame、initWithCoder、awakeFromNib的区别和调用次序 & UIViewController生命周期 查缺补漏
		
当我们创建或者自定义一个UI控件时,就很可能会调用awakeFromNib.initWithCoder .initWithFrame这些方法.三者的具体区别如下: initWithFrame: 通过代 ...
 - IOS应用程序生命周期&启动周期函数
		
—程序的生命周期 a.程序的生命周期是指应用程序启动到应用程序结束整个阶段的全过程 b.每一个IOS应用程序都包含一个UIApplication对象,IOS系统通过该U ...
 - UIViewController生命周期控制
		
UIViewController生命周期控制 UIViewController介绍 官方的介绍例如以下 The UIViewController class provides the fundamen ...
 - 你真的了解UIViewController生命周期吗?
		
一:首先了解一下生命周期图 二:UIViewController 生命周期介绍 1.通过alloc init 分配内存,初始化controller. 2.loadView loadView方法默认实现 ...
 - (转)iOS应用程序生命周期(前后台切换,应用的各种状态)详解
		
原文:http://blog.csdn.net/totogo2010/article/details/8048652 iOS应用程序生命周期(前后台切换,应用的各种状态)详解 分类: ...
 - 转:iOS应用程序生命周期(前后台切换,应用的各种状态)详解
		
iOS应用程序生命周期(前后台切换,应用的各种状态)详解 分类: iOS开发进阶2012-10-08 15:35 42691人阅读 评论(30) 收藏 举报 iosapplication任务anima ...
 - UIViewController生命周期
		
UIViewController生命周期
 
随机推荐
- HDU 5828 Rikka with Sequence
			
好久没写线段树了,这题作为一个回味.. 第一种操作的话,就是一个延迟标记. 第二种操作可以暴力更新下去,但是有一个优化,如果某区间内所有值都是一样的,或者最大值和最小值相差1,那么到此结束,不要继续往 ...
 - HDU 5769 Substring
			
后缀数组. 然后按照排序完成之后的顺序,每个后缀统计贡献量. 统计第i个后缀的贡献的时候,如果这个后缀中没有X,贡献度为0. 有贡献的分3种情况考虑: 1.如果这个后缀height部分等于0(即与前一 ...
 - python2.7学习记录之四
			
1.从raw_input()读取的内容永远以字符串的形式返回,把字符串和整数比较就不会得到期待的结果,必须先用int()把字符串转换为我们想要的整型 2.list增加元素 为 append() 3.d ...
 - 批量创建IP方法
			
以下教程,将告诉大家如何在Windows系统中通过命令行,批量添加IP.目标,在本机的的网卡名称为“本地连接”的网卡中,批量添加192.168.1段的ip地址,起开始IP为10,每次增加1,知道22为 ...
 - Linux设置开机服务自动启动
			
[root@localhost ~]# chkconfig --list 显示开机可以自动启动的服务[root@localhost ~]# chkconfig --add *** 添加开机自 ...
 - Web开发人员不要错过的60款用户界面设计工具(上)
			
Web开发大师们,干货再次来袭!小编为大家盘点了60款功能丰富类型各异的用户界面设计工具,本系列将以上中下三篇分别为大家呈现.今天盘点的这20款工具囊括了大量界面原型设计工具,有免费的在线原型工具,有 ...
 - mysql 表连接
			
1.子查询是指在另一个查询语句中的SELECT子句. 例句: SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2); 其中,SELECT ...
 - mac随手笔记
			
在mac下安装有时候遇到一个问题,需要sudo指令来解决. sudo是linux系统管理指令,是允许系统管理员让普通用户执行一些或者全部的root命令的一个工具,如halt,reboot,su等等.这 ...
 - As3.0 视频缓冲、下载总结
			
来源:http://www.cuplayer.com/player/PlayerCodeAs/2012/0913404.html 利用NetStream的以下属性: bufferTime — 缓冲区大 ...
 - Spring Security教程
			
原文地址:http://blog.csdn.net/jaune161/article/details/17640071 http://blog.csdn.net/jaune161/article/de ...