跳到主要内容

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 中操作即可。

相关链接​