UIView和UIViewController是UIKit中负责和控制展示与交互的核心类,通常将从它们的创建到视图加载(load)、显示(display)、移除(remove)的过程称为视图的生命周期,清楚这个周期内系统函数的执行顺序,有助于开发者掌控视图的展示过程,在合适的地方添加代码来实现自己的需求。
构建
UIView和UIViewController有三种创建方式:code(代码)、xib和storyboard,任何构建方式最后都需要调用指定构造方法(NS_DESIGNATED_INITIALIZER),它们各有两个指定构造方法,不同创建方式在指定构造方法调用前后执行的函数各有不同:
构建顺序 | UIView | UIViewController |
---|---|---|
code | -initWithFrame: | -init(或其它自定义构造方法) -initWithNibName: bundle: |
xib | -initWithCoder: -awakeFromNib: |
-init(隐式使用xib) -initWithNibName: bundle: |
storyboard | -initWithCoder: -awakeFromNib: |
-initWithCoder: -awakeFromNib: |
构建过程容易混淆的地方主要有以下两点:
- UIView通过xib和storyboard创建时调用了
-initWithCoder:
和-awakeFromNib:
,UIViewController通过toryboard创建时也调用了它们,通过xib创建时调用的却不是它们; - 通过xib创建UIViewController时调用的是
-initWithNibName: bundle:
,而通过code创建时调用的也是这个指定构造函数;
加载
当ViewController创建后,它的根视图是懒加载的,加载前后会分别调用-loadView
和-viewDidLoad
函数,关于ViewController的根视图加载过程需要注意以下几点:
-loadView
和-viewDidLoad
都需要触发根视图的加载过程才会被调用,如果没有触发根视图的加载过程(view在使用前通过代码赋了非空的值),则它们都不会执行;-loadView
中可以设置根视图,这儿设置的根视图,可以覆盖xib创建的根视图,但会被storyboard创建的根视图覆盖;
显示
ViewController展示它的视图和View被添加到superview上显示时函数调用顺序如下:
UIViewController | UIView |
---|---|
-viewWillAppear: -loadViewIfNeeded -viewWillLayoutSubviews -viewDidLayoutSubviews -viewDidAppear: -viewWillLayoutSubviews -viewDidLayoutSubviews |
-willMoveToSuperview: -didMoveToSuperview -willMoveToWindow: -didMoveToWindow |
显示过程需要注意的有:
-viewWillAppear:
之后会自动调用-loadViewIfNeeded
,确保根视图已完成加载;- LayoutSubviews相关方法在
-viewWillAppear:
和-viewDidAppear:
前后都会被调用;
移除
ViewController的视图不再展示和View从superview上移除时调用的函数顺序如下:
| UIViewController | UIView |
| — | — |
| -viewWillDisappear:
-viewWillLayoutSubviews
-viewDidLayoutSubviews
-viewDidDisappear: | -willMoveToSuperview:
-willMoveToWindow:
-didMoveToWindow
-didMoveToSuperview |
关于ViewController的disappear和View的移除需要注意的是:
- disappear过程也会触发LayoutSubviews相关方法;
- View的MoveToWindow和MoveToSuperview方法之间的顺序难以保证(只能确定will和did的先后顺序);
汇总
以展示一个通过code创建的ViewController,并在-viewDidLoad
方法中添加了一个subView为例,视图生命周期相关函数的交叉顺序如下:
1 | // Appear过程 |