跳到主要内容

UIViewController 生命周期

问题

UIViewController 的生命周期方法有哪些?页面跳转时各 VC 的回调顺序是什么?

答案

完整生命周期

各方法用途

方法调用时机常见用途
loadView创建 view 层级自定义 root view(不调 super)
viewDidLoadview 加载到内存后(仅一次)初始化 UI、网络请求
viewWillAppearview 即将显示刷新数据、注册通知
viewDidAppearview 已显示启动动画、开始定位
viewWillDisappearview 即将消失保存数据、注销通知
viewDidDisappearview 已消失释放资源
viewWillLayoutSubviews即将布局子视图调整 frame
viewDidLayoutSubviews布局完成获取最终 frame

页面跳转的回调顺序

Push B:

A: viewWillDisappear
B: viewWillAppear
A: viewDidDisappear
B: viewDidAppear

Pop B(返回 A):

B: viewWillDisappear
A: viewWillAppear
B: viewDidDisappear
A: viewDidAppear
B: deinit

Present B(模态):

// iOS 13+ 默认 .automatic(pageSheet,A 不触发 disappear)
B: viewWillAppear
B: viewDidAppear

// .fullScreen
A: viewWillDisappear
B: viewWillAppear
A: viewDidDisappear
B: viewDidAppear
iOS 13 模态变化

iOS 13+ 默认模态样式为 .pageSheet(非全屏),此时 A 的 viewWillDisappear / viewDidDisappear 不会被调用。如果需要全屏模态,需设置 modalPresentationStyle = .fullScreen

View 的布局触发流程

  • setNeedsLayout:标记需要重新布局(异步,不立即执行)
  • layoutIfNeeded:如果有标记,立即执行布局
  • layoutSubviews:实际执行布局,子类重写(必须调 super)

常见面试问题

Q1: viewDidLoad 和 viewWillAppear 的区别?

答案

  • viewDidLoad:view 第一次加载到内存时调用,只调一次。适合做初始化配置
  • viewWillAppear:每次 view 即将显示时都会调用(push 回来也会调)。适合做数据刷新

Q2: 如何保证在获取到正确的 frame 后再做操作?

答案:在 viewDidLayoutSubviews 中操作,此时 AutoLayout 已计算完毕。注意该方法可能被多次调用。

Q3: loadView 什么时候需要重写?

答案:当你需要完全自定义 root view 时(不使用 Storyboard/Xib 且不需要默认的 UIView):

override func loadView() {
// 不要调 super.loadView()
view = MyCustomView()
}

如果只是在默认 view 上添加子视图,在 viewDidLoad 中操作即可。

相关链接