一、UIViewController 生命周期核心流程(以 iOS 13 + 为例)
先通过流程图直观理解整体顺序:

graph TD
A[初始化 init] --> B[加载视图 loadView]
B --> C[视图加载完成 viewDidLoad]
C --> D[视图将要出现 viewWillAppear:]
D --> E[视图布局更新 viewWillLayoutSubviews]
E --> F[视图布局完成 viewDidLayoutSubviews]
F --> G[视图已经出现 viewDidAppear:]
%% 页面消失流程
G --> H[视图将要消失 viewWillDisappear:]
H --> I[视图已经消失 viewDidDisappear:]
%% 内存警告/销毁流程
I --> J{是否销毁?}
J -->|是| K[视图卸载 viewDidUnload - 已废弃]
J -->|是| L[销毁 dealloc]
J -->|否| D
%% 内存警告分支
C --> M[收到内存警告 didReceiveMemoryWarning]
M --> N[释放非必要资源]
N --> D
是
是
否
初始化 init
加载视图 loadView
视图加载完成 viewDidLoad
视图将要出现 viewWillAppear:
视图布局更新 viewWillLayoutSubviews
视图布局完成 viewDidLayoutSubviews
视图已经出现 viewDidAppear:
视图将要消失 viewWillDisappear:
视图已经消失 viewDidDisappear:
是否销毁?
视图卸载 viewDidUnload - 已废弃
销毁 dealloc
收到内存警告 didReceiveMemoryWarning
释放非必要资源
二、核心方法详解(新手友好版)
| 方法名 | 作用 & 使用场景 |
|---|---|
init / initWithNibName:bundle: |
控制器初始化,仅分配内存,不要在这里创建 UI 控件(视图还没加载),适合初始化数据模型。 |
loadView |
系统自动调用,用于创建控制器的view(根视图)。⚠️ 新手注意:不要主动调用,也不要重写除非你要自定义根视图(比如用纯代码替代 xib/storyboard)。 |
viewDidLoad |
视图加载完成后调用(仅调用一次)。✅ 核心场景:创建 UI 控件、设置控件属性、网络请求初始化、数据绑定(比如给 tableView 设数据源)。 |
viewWillAppear: |
视图即将显示在屏幕上时调用(每次页面显示都会触发,比如从后台切回、跳转返回)。✅ 场景:刷新数据、设置导航栏 / 状态栏样式、开启定时器 / 监听。 |
viewWillLayoutSubviews |
视图即将布局子控件时调用(比如屏幕旋转、view 大小变化)。✅ 场景:调整控件布局(比如手动计算 frame)。 |
viewDidLayoutSubviews |
视图子控件布局完成后调用。✅ 场景:获取控件最终的 frame/size(比如 scrollView 的 contentSize)。 |
viewDidAppear: |
视图已经显示在屏幕上时调用。✅ 场景:执行动画、开始播放视频 / 音频、请求定位权限。 |
viewWillDisappear: |
视图即将从屏幕消失时调用。✅ 场景:关闭定时器、移除监听、保存数据、隐藏键盘。 |
viewDidDisappear: |
视图已经消失时调用。✅ 场景:停止网络请求、释放临时资源。 |
didReceiveMemoryWarning |
系统内存不足时调用。✅ 场景:释放缓存、图片、非必要的对象(注意不要释放正在使用的资源)。 |
dealloc |
控制器销毁时调用(ARC 自动管理)。✅ 场景:最后清理资源(比如移除所有监听、释放自定义的强引用对象)。 |
三、简单代码示例
objective-c
#import <UIKit/UIKit.h>
@interface TestViewController : UIViewController
@end
@implementation TestViewController
// 1. 初始化
- (instancetype)init {
self = [super init];
if (self) {
NSLog(@"1. 控制器初始化 init");
// 初始化数据模型
self.title = @"测试页面";
}
return self;
}
// 2. 加载视图(一般不重写)
- (void)loadView {
[super loadView];
NSLog(@"2. 加载视图 loadView");
// 若自定义根视图,可在这里设置:self.view = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
}
// 3. 视图加载完成(仅一次)
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"3. 视图加载完成 viewDidLoad");
// 创建UI控件
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(100, 100, 200, 50);
[btn setTitle:@"测试按钮" forState:UIControlStateNormal];
[self.view addSubview:btn];
}
// 4. 视图即将显示
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(@"4. 视图即将显示 viewWillAppear:");
// 刷新数据
self.navigationController.navigationBarHidden = NO;
}
// 5. 视图即将布局子控件
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
NSLog(@"5. 视图即将布局子控件 viewWillLayoutSubviews");
}
// 6. 视图布局子控件完成
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
NSLog(@"6. 视图布局子控件完成 viewDidLayoutSubviews");
// 获取控件最终尺寸
NSLog(@"按钮宽度:%f", self.view.subviews.firstObject.frame.size.width);
}
// 7. 视图已经显示
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(@"7. 视图已经显示 viewDidAppear:");
// 执行动画
[UIView animateWithDuration:0.3 animations:^{
self.view.subviews.firstObject.alpha = 1.0;
}];
}
// 8. 视图即将消失
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
NSLog(@"8. 视图即将消失 viewWillDisappear:");
// 关闭定时器/监听
}
// 9. 视图已经消失
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
NSLog(@"9. 视图已经消失 viewDidDisappear:");
}
// 10. 内存警告
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
NSLog(@"10. 收到内存警告 didReceiveMemoryWarning");
// 释放缓存
}
// 11. 销毁
- (void)dealloc {
NSLog(@"11. 控制器销毁 dealloc");
// 最终清理
}
@end
运行输出顺序(首次进入页面):
plaintext
1. 控制器初始化 init
2. 加载视图 loadView
3. 视图加载完成 viewDidLoad
4. 视图即将显示 viewWillAppear:
5. 视图即将布局子控件 viewWillLayoutSubviews
6. 视图布局子控件完成 viewDidLayoutSubviews
7. 视图已经显示 viewDidAppear:
返回上一页时输出:
plaintext
8. 视图即将消失 viewWillDisappear:
9. 视图已经消失 viewDidDisappear:
11. 控制器销毁 dealloc
总结
- 核心顺序 :
init→loadView→viewDidLoad→viewWillAppear:→viewWillLayoutSubviews→viewDidLayoutSubviews→viewDidAppear:→viewWillDisappear:→viewDidDisappear:→dealloc。 - 关键区分 :
viewDidLoad仅调用一次(适合初始化 UI),viewWillAppear:/viewDidAppear:每次显示都调用(适合刷新数据 / 执行动画)。 - 内存管理 :
didReceiveMemoryWarning释放非必要资源,dealloc做最终清理,避免内存泄漏。