六、UIView的生命周期

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:

构建过程容易混淆的地方主要有以下两点:

  1. UIView通过xib和storyboard创建时调用了-initWithCoder:-awakeFromNib:,UIViewController通过toryboard创建时也调用了它们,通过xib创建时调用的却不是它们;
  2. 通过xib创建UIViewController时调用的是-initWithNibName: bundle:,而通过code创建时调用的也是这个指定构造函数;

加载

当ViewController创建后,它的根视图是懒加载的,加载前后会分别调用-loadView-viewDidLoad函数,关于ViewController的根视图加载过程需要注意以下几点:

  1. -loadView-viewDidLoad都需要触发根视图的加载过程才会被调用,如果没有触发根视图的加载过程(view在使用前通过代码赋了非空的值),则它们都不会执行;
  2. -loadView中可以设置根视图,这儿设置的根视图,可以覆盖xib创建的根视图,但会被storyboard创建的根视图覆盖;

显示

ViewController展示它的视图和View被添加到superview上显示时函数调用顺序如下:

UIViewController UIView
-viewWillAppear:
-loadViewIfNeeded
-viewWillLayoutSubviews
-viewDidLayoutSubviews
-viewDidAppear:
-viewWillLayoutSubviews
-viewDidLayoutSubviews
-willMoveToSuperview:
-didMoveToSuperview
-willMoveToWindow:
-didMoveToWindow

显示过程需要注意的有:

  1. -viewWillAppear:之后会自动调用-loadViewIfNeeded,确保根视图已完成加载;
  2. LayoutSubviews相关方法在-viewWillAppear:-viewDidAppear:前后都会被调用;

移除

ViewController的视图不再展示和View从superview上移除时调用的函数顺序如下:
| UIViewController | UIView |
| — | — |
| -viewWillDisappear:
-viewWillLayoutSubviews
-viewDidLayoutSubviews
-viewDidDisappear: | -willMoveToSuperview:
-willMoveToWindow:
-didMoveToWindow
-didMoveToSuperview |

关于ViewController的disappear和View的移除需要注意的是:

  1. disappear过程也会触发LayoutSubviews相关方法;
  2. View的MoveToWindow和MoveToSuperview方法之间的顺序难以保证(只能确定will和did的先后顺序);

汇总

以展示一个通过code创建的ViewController,并在-viewDidLoad方法中添加了一个subView为例,视图生命周期相关函数的交叉顺序如下:

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
27
28
29
// Appear过程
-[ViewController init]
-[ViewController initWithNibName:bundle:]
-[ViewController loadView]
-[ViewController viewDidLoad]
-[SubView initWithFrame:]
-[SubView willMoveToSuperview:]
-[SubView didMoveToSuperview]
-[ViewController viewWillAppear:]
-[ViewController loadViewIfNeeded]
-[SubView willMoveToWindow:]
-[SubView didMoveToWindow]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]
-[SubView layoutSubviews]
-[SubView layoutSubviews]
-[ViewController viewDidAppear:]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]

// Disappear过程
-[ViewController viewWillDisappear:]
-[ViewController viewWillLayoutSubviews]
-[ViewController viewDidLayoutSubviews]
-[SubView willMoveToWindow:]
-[SubView didMoveToWindow]
-[ViewController viewDidDisappear:]
-[SubView willMoveToSuperview:]
-[SubView didMoveToSuperview]
-------------This article is over, thank you for reading -------------