UIViewController及生命周期

UIViewController是UIKit框架中Controller部分的基础
所有界面都是基于UIViewController搭建出来的

UIViewController的生命周期

生命周期指对象从创建到被销毁的整个过程,保持内存的平衡和而程序高效运行
当需要一个对象时,他会被创建并分配内存空间
当它不再被需要时,应该被系统释放回收
UIViewController对象从创建到释放过程中会依次调用许多生命周期函数

打开Xcode,创建一个名为UIViewControllerTest的工程
创建工程操作见上一篇:IOS开发实战-Xcode创建HelloWorld项目

创建完成后,模板代码会自动生成一个ViewController类

iOS子控制器的生命周期 ios开发控制器生命周期_加载

ViewController类继承自UIViewController,

并与Main,storyboard中初始视图控制器关联,

简单来说,这个类创建了一个视图控制器,作为工程的根视图控制器

iOS子控制器的生命周期 ios开发控制器生命周期_加载_02

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输出:

iOS子控制器的生命周期 ios开发控制器生命周期_加载_03

从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