news 2026/6/10 23:14:42

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/6/10 10:58:39

Zotero PDF翻译插件:如何实现英文文献一键中文化?

Zotero PDF翻译插件&#xff1a;如何实现英文文献一键中文化&#xff1f; 【免费下载链接】zotero-pdf2zh PDF2zh for Zotero | Zotero PDF中文翻译插件 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-pdf2zh 还在为阅读英文文献而头疼吗&#xff1f;Zotero PDF翻…

作者头像 李华
网站建设 2026/6/10 10:58:44

FabricMC加载器深度探索:如何构建高性能模组生态系统

FabricMC加载器深度探索&#xff1a;如何构建高性能模组生态系统 【免费下载链接】fabric-loader Fabrics mostly-version-independent mod loader. 项目地址: https://gitcode.com/gh_mirrors/fa/fabric-loader FabricMC fabric-loader作为Minecraft游戏中的轻量级模组…

作者头像 李华
网站建设 2026/6/10 10:58:18

基于GLM-4.6V-Flash-WEB构建图文混合输入系统的最佳实践

基于GLM-4.6V-Flash-WEB构建图文混合输入系统的最佳实践 在今天的AI应用开发中&#xff0c;一个越来越常见的需求是&#xff1a;用户上传一张图&#xff0c;再提一个问题——比如“这张发票的金额是多少&#xff1f;”、“这个商品有没有促销信息&#xff1f;”、“这份报告的关…

作者头像 李华
网站建设 2026/6/9 16:31:14

【独家揭秘】:Dify如何在毫秒级完成复杂DOCX文档解析

第一章&#xff1a;Dify DOCX处理优化的背景与挑战在现代企业级文档自动化系统中&#xff0c;Dify 作为集成了大语言模型能力的低代码平台&#xff0c;承担着大量 DOCX 文档的动态生成与内容填充任务。随着业务场景复杂度提升&#xff0c;传统基于模板替换的 DOCX 处理方式暴露…

作者头像 李华
网站建设 2026/6/10 10:58:33

【Dify附件ID存在性验证】:3步实现高效校验与异常处理策略

第一章&#xff1a;Dify附件ID存在性验证概述在构建基于 Dify 的自动化工作流时&#xff0c;确保附件 ID 的有效性是保障数据完整性和流程稳定性的关键环节。当用户上传文件并引用其 ID 进行后续处理时&#xff0c;系统必须验证该 ID 是否真实存在、是否已被删除或过期。若缺乏…

作者头像 李华
网站建设 2026/6/10 12:33:33

问卷设计还在 “凭感觉”?虎贲等考 AI 让学术调研精准出圈

做学术调研时&#xff0c;你是否陷入过这样的困境&#xff1a;手动设计问卷漏洞百出&#xff0c;要么题项逻辑混乱、要么量表不科学&#xff0c;回收数据后才发现 “无效问卷占一半”&#xff1b;好不容易做完调研&#xff0c;数据分析无从下手&#xff0c;统计结果缺乏说服力。…

作者头像 李华