news 2026/4/25 17:19:19

iOS - UIViewController 生命周期

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
iOS - UIViewController 生命周期

一、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

总结

  1. 核心顺序initloadViewviewDidLoadviewWillAppear:viewWillLayoutSubviewsviewDidLayoutSubviewsviewDidAppear:viewWillDisappear:viewDidDisappear:dealloc
  2. 关键区分viewDidLoad仅调用一次(适合初始化 UI),viewWillAppear:/viewDidAppear:每次显示都调用(适合刷新数据 / 执行动画)。
  3. 内存管理didReceiveMemoryWarning释放非必要资源,dealloc做最终清理,避免内存泄漏。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 5:34:40

Kodi中文插件库终极配置指南:5步打造完美家庭影院

还在为Kodi缺少中文资源而烦恼&#xff1f;想要一键解锁海量本土化影视内容&#xff1f;这份完整的Kodi中文插件库配置手册将带你从零开始&#xff0c;彻底解决中文用户的使用痛点&#xff0c;让你的家庭影院体验焕然一新&#xff01; 【免费下载链接】xbmc-addons-chinese Add…

作者头像 李华
网站建设 2026/4/22 19:37:40

Real-ESRGAN轻量化架构深度解析:6残差块实现动漫图像4K级超分辨率

Real-ESRGAN作为当前最实用的图像视频修复算法之一&#xff0c;其轻量化版本RealESRGAN_x4plus_anime_6B通过仅6个残差块的巧妙设计&#xff0c;在动漫图像4倍放大任务中实现了专业级效果。本文将深入探讨这一技术突破的核心原理&#xff0c;并提供从基础应用到高级定制的完整解…

作者头像 李华
网站建设 2026/4/17 15:24:24

Dify access_token 刷新失败的7大原因及对应解决方案

第一章&#xff1a;Dify access_token 异常在使用 Dify 平台进行 API 集成时&#xff0c;开发者可能会遇到 access_token 异常问题&#xff0c;导致请求被拒绝或返回 401 错误。这类问题通常与认证流程、令牌过期机制或权限配置有关。常见异常表现 HTTP 401 Unauthorized 响应返…

作者头像 李华
网站建设 2026/4/23 17:13:52

轻松上手GLM-4.6V-Flash-WEB:开发者友好的开源模型

轻松上手GLM-4.6V-Flash-WEB&#xff1a;开发者友好的开源模型 在智能客服系统中&#xff0c;用户上传一张订单截图并提问&#xff1a;“这个包裹什么时候能到&#xff1f;”——传统OCR只能提取文字信息&#xff0c;却无法理解图像与问题之间的语义关联。而如今&#xff0c;越…

作者头像 李华