UIViewController及生命周期
UIViewController是UIKit框架中Controller部分的基础
所有界面都是基于UIViewController搭建出来的
UIViewController的生命周期
生命周期指对象从创建到被销毁的整个过程,保持内存的平衡和而程序高效运行
当需要一个对象时,他会被创建并分配内存空间
当它不再被需要时,应该被系统释放回收
UIViewController对象从创建到释放过程中会依次调用许多生命周期函数
打开Xcode,创建一个名为UIViewControllerTest的工程
创建工程操作见上一篇:IOS开发实战-Xcode创建HelloWorld项目
创建完成后,模板代码会自动生成一个ViewController类
ViewController类继承自UIViewController,
并与Main,storyboard中初始视图控制器关联,
简单来说,这个类创建了一个视图控制器,作为工程的根视图控制器
UIViewController中生命周期相关函数:
// 类的初始化方法
+ (void)initialize;
// 对象初始化方法
- (instancetype)init;
// 从归档初始化
- (instancetype)initWithCoder:(NSCoder *)coder;
// Xib初始化后
-(void)awakeFromNib;
// 加载视图
-(void)loadView;
// 将要加载视图
- (void)viewDidLoad;
// 将要布局子视图
-(void)viewWillLayoutSubviews;
// 已经布局子视图
-(void)viewDidLayoutSubviews;
// 内存警告
- (void)didReceiveMemoryWarning;
// 将要展示
-(void)viewWillAppear:(BOOL)animated;
// 已经展示
-(void)viewDidAppear:(BOOL)animated;
// 将要消失
-(void)viewWillDisappear:(BOOL)animated;
// 已经消失
-(void)viewDidDisappear:(BOOL)animated;
// 被释放
-(void)dealloc;
在ViewController.m中覆写UIViewController方法
测试并跟踪声明周期函数的执行顺序:
//
// ViewController.m
// UIViewController
//
// Created by Brave on 18/4/29.
// Copyright © 2018年 com.Brave. All rights reserved.
//
#import "ViewController.h"
int tip = 0;// 对程序运行过程进行标记
@interface ViewController ()
@end
// ViewController是UIViewController的子类
@implementation ViewController
// 类的初始化方法
+(void)initialize{
// 在子类中覆盖父类方法时,需先调用父类此方法
[super initialize];
NSLog(@"%d initialize", ++tip);
}
// 对象初始化方法
// 只允许调用一次,并且要与 alloc方法 写在一起,
// 在init方法中申请的内存,要在dealloc方法中释放(或者其他地方);
- (instancetype)init{
self=[super init];
if(self){
}
NSLog(@"%d init", ++tip);
return self;
}
// 从归档初始化
- (instancetype)initWithCoder:(NSCoder *)coder{
self = [super initWithCoder:coder];
if(self){
}
NSLog(@"%d initWithCoder", ++tip);
return self;
}
// 使用Xib初始化后会调用此方法,一般不会重写此方法;
-(void)awakeFromNib{
[super awakeFromNib];
NSLog(@"%d awakeFromNib", ++tip);
}
// 加载视图
// 如果使用Xib创建ViewController,就不要重写该方法。一般不会修改此方法
-(void)loadView{
[super loadView];
NSLog(@"%d loadView", ++tip);
}
// 将要加载视图
// 视图加载完成之后被调用,这个方法很重要,可以在此增加一些自己定义的控件,
// 注意,此时view的frame不一定是显示时候的frame,真实的frame会在 - (void)viewDidAppear: 后。
// 在iOS6.0+版本中在对象的整个生命周期中只会被调用一次
// 这里要注意在iOS3.0~iOS5.X版本中可能会被重复调用,
// 当ViewController收到内存警告后,会释放View,并调用viewDidUnload,
// 之后会重新调用viewDidLoad,所以要支持iOS6.0以前版本的童鞋要注意这里的内存管理。
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%d viewDidLoad", ++tip);
// Do any additional setup after loading the view, typically from a nib.
}
// 将要布局子视图
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
NSLog(@"%d viewWillLayoutSubviews", ++tip);
}
// 已经布局子视图
-(void)viewDidLayoutSubviews{
[super viewDidLayoutSubviews];
NSLog(@"%d viewDidLayoutSubviews", ++tip);
}
// 内存警告
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
NSLog(@"%d didReceiveMemoryWarning", ++tip);
// Dispose of any resources that can be recreated.
}
// 将要展示
// 可在此处加载图片,和其他占内存的资源
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSLog(@"%d viewWillAppear", ++tip);
}
// 已经展示
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
NSLog(@"%d viewDidAppear", ++tip);
}
// 将要消失
// 可在此将占用内存比较大的资源先释放掉,在viewWillAppear: 中重新加载,如:图片/声音/视频。
// 如果View已经隐藏而又在内存中保留这些在显示前不会被调用的资源,
// 那么App闪退的几率会增加,尤其是ViewController比较多的时候;
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
NSLog(@"%d viewWillDisappear", ++tip);
}
// 已经消失
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
NSLog(@"%d viewDidDisappear", ++tip);
}
// 被释放
// dealloc方法时唯一一个不需要并且也不能在实现时调用父类方法的函数,
// 这个函数在ARC(自动引用计数)环境中不再被开发者需要,
// 但开发者依然可以重写这个函数来检测内存的释放情况
// 不要手动调用此方法,当引用计数值为0的时候,系统会自动调用此方法。
-(void)dealloc{
NSLog(@"%d dealloc", ++tip);
}
@end
以上代码在ViewController.m中创建了一个全局变量tip
使用tip对程序运行过程进行标记,通过log日志查看函数执行顺序
执行程序,观察Log输出:
从Log中可以清晰看到UIViewController创建时的生命周期函数调用顺序
(不包括销毁过程及从不同来源初始化UIViewController的过程)
initialize:
并不会在每次创建对象时被调用,
只在这个类第一次创建对象时被调用做一些类的准备工作
如果有继承的子类未实现initialize方法,
第一次创建子类对象时,父类会代替子类调用initialize方法
init和initWithCoder都是用作初始化对象
init:从代码进行初始化
initWithCoder:从归档文件进行初始化
awakeFromNib:
从xib或storyboard中加载UIViewController将要被激活时调用
loadView:
加载UI视图初始化方法,UIViewController生命周期中只调用一次
viewDidLoad:
视图加载完成后调用,此时视图控制器基本工程已初始化完成
一般将一些Controller额外定义功能的初始化工作放在此函数中
viewWillAppear:
视图即将显示时调用
viewWillLayoutSubviews:
视图将要布局其子视图时被调用
viewDidLaySubviews:
视图布局完成其子视图时被调用
viewDidAppear
视图显示后被调用
UIViewController被释放和销毁的过程调用:
viewWillDisappear:
在试图将要消失时调用,做一些数据保存和清理工作
viewDidDisappear
视图已经消失时调用
dealloc或deinit
对象的销毁方法,在对象释放时调用,
可通过在其中打印信息检查是否存在内存泄露等问题
UIViewController的视图层级结构:
UIViewController自带一个UIView类型的view视图
这个view平铺在屏幕上,是视图控制器的根视图
在视图控制器中添加UI控件都是添加在这个view上
UIView通过addSubview方法添加子view视图
子view视图也可以继续使用addsubview添加自己的子视图......
备注:
Xcode模拟器的Home键:Command-Shift-H