iOS 关于控制器的生命周期 - AlvinSunny/OC-TheUnderlying GitHub Wiki

控制器相关

1> initWithCoder:(NSCoder *)aDecoder : 如果使用storyboard或者xib

2> loadView : 加载view

3> viewDidLoad : view加载完毕

4> viewWillAppear: : 控制器的view将要显示

5>viewWillLayoutSubviews : 控制器的view将要布局子控件

6> viewDidLayoutSubviews : 控制器的view布局子控件完成

7> viewDidAppear: : 控制器的view完全显示

8> viewWillDisappear: 控制器的view即将消失

9> viewDidDisappear: : 控制器的view完全消失

10> didReceiveMemoryWarning: 程序发出内存警告,系统会询问控制器有view吗? 如果有且不在window上就销毁,执行viewWillUnLoad对view进行一次release 此时view就为nil,然后调用viewDidUnLoad 一般还会再这个方法里将一些不需要的属性清空

11> dealloc : 控制器引用计数为0

控制器跳转

当push下一个控制器时,两个控制器的生命周期方法是交替调用的,以保证流畅性和很好的用户体验;

ViewController1跳ViewController2

ViewController2 - loadView   加载控制器view
ViewController2 - viewDidLoad   控制器的view加载完成
ViewController1 - viewWillDisappear   即将消失
ViewController2 - viewWillAppear     即将出现                           
ViewController2 - viewWillLayoutSubviews    即将布局控制器view的子控件
ViewController2 - viewDidLayoutSubviews    完成控制器view子控件布局
ViewController1 - viewDidDisappear    完全消失
ViewController2 - viewDidAppear    完全出现

ViewController2跳回ViewController1

ViewController2 - viewWillDisappear     控制器即将消失
ViewController1 - viewWillAppear     控制器即将出现
ViewController2 - viewDidDisappear     控制器完全消失
ViewController1 - viewDidAppear     控制器完全出现
ViewController2 - dealloc     控制器释放

一个视图想要显示出来首先就需要先加载出来, 然后才能够显示, 所以 viewDidLoad 一定是在 viewWillAppear 之前调用;

如果是present方式的modalPresentationStyle是UIModalPresentationFullScreen,生命周期方法和push相同 如果是present方式的modalPresentationStyle不是UIModalPresentationFullScreen,只会走ViewController2自己的生命周期方法,ViewController1因为没有完全消失所以不会走生命周期方法

ViewController2 - loadView    加载视图
ViewController2 - viewDidLoad     加载完成视图
ViewController2 - viewWillAppear    将要显示视图
ViewController2 - viewWillLayoutSubviews    将要开始布局子控件
ViewController2 - viewDidLayoutSubviews     布局子控件完成
ViewController2 - viewDidAppear    显示视图完成

生命周期方法详解:

loadView: 若控制器有关联的Nib文件,该方法会从Nib文件中加载view ,如果没有且实现[super loadView] 则创建空白UIView对象 重写该方法以自定义控制器view ,自定义实现不应该再调用父类的该方法

坑点:

控制器未关联的Nib,重写loadView方法未实现[super loadView] ,push该控制器时会出现多次反复调用loadView 、viewDidLoad 后 直接来到viewDidAppear 后面的生命周期方法不会走了 显示黑屏

- (void)loadView {
    NSLog(@"ViewController2 - loadView");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"ViewController2 - viewDidLoad");
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"ViewController2 - viewDidAppear");
}

push进来的打印结果: 
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - viewDidAppear

pop出去的打印结果: 
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - viewWillDisappear
ViewController1 - viewWillAppear
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - viewDidDisappear
ViewController1 - viewDidAppear
ViewController2 - dealloc


控制器未关联的Nib,重写loadView方法实现了[super loadView],push该控制器时会走正常的生命周期方法 但依然显示黑屏

控制器未关联的Nib,重写loadView方法未实现[super loadView]且在 viewDidLoad 中使用了self.view, 这会引起系统无数次重复调用loadView 直至程序崩溃 Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ff7b3f4aff8), 因为要使用view有不给控制器设置view, 这就会造成系统不断的尝试通过loadView获取view

ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
ViewController2 - loadView
ViewController2 - viewDidLoad
........死循环
ViewController2 - loadView
ViewController2 - viewDidLoad
崩溃 Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ff7b3f4aff8)

viewDidLoad: view被加载到内存后调用viewDidLoad, 重写该方法需要首先调用父类的该方法 该方法中可以额外初始化控件,例如:添加子控件 添加约束 该方法被调用意味着控制器有可能(并非一定)在未来会显示出来,在控制器生命周期中该方法一般只会被调用一次

viewWillAppear:
该方法在控制器view即将添加到视图层次时以及展示view时所有动画配置前被调用 重写该方法需要首先调用父类该方法 该方法中可以进行操作即将显示的view , 例如:改变状态栏的取向、类型 该方法被调用意味着控制器将一定会显示,在控制器生命周期中,该方法可能会被多次调用

viewWillLayoutSubviews: 该方法在通知控制器将要布局view的子控件时调用,每当视图的边界(bounds)发生改变(横竖屏、手动修改bounds)或给控制器的view添加新的子控件时(addSubview:),view将调整其子控件位置 该方法可重写以在view布局子控件前做出改变,默认实现为空 该方法调用时AutoLayout未起作用,在控制器生命周期中会被多次调用

viewDidLayoutSubviews: 该方法在通知控制器已经布局好view的子控件时调用 该方法可重写以在view布局完子控件后做出改变,默认实现为空 该方法调用时,AutoLayout已经完成,在控制器生命周期中会被多次调用

viewDidAppear: 该方法在控制器view已经添加到视图层次时被调用 重写该方法需要先调用父类方法 该方法可重写以进行有关正在展示的视图操作,在控制器生命周期中会被多次调用

viewWillDisappear: 该方法在控制器view即将从视图层移除时被调用 该方法可重写以提交变更 取消视图第一响应者状态

viewDidDisappear: 该方法在控制器view已经从视图层次移除时被调用 该方法可重写以清除或隐藏控件

didReceiveMemoryWarning: 当内存警告是该方法被调用, 不能手动调用该方法,该方法可重写以释放资源、内存

dealloc: 控制器销毁是调用该方法释放当前示例以外需要手动管理内存的资源