news 2026/1/10 1:57:28

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/1/7 10:09:45

你还在手动写API文档?Dify Flask-Restx 自动化方案让效率翻倍

第一章&#xff1a;你还在手动写API文档&#xff1f;Dify Flask-Restx 自动化方案让效率翻倍在现代后端开发中&#xff0c;API 文档的维护常常耗费大量时间。传统的手写文档方式不仅容易出错&#xff0c;还难以与代码同步更新。借助 Dify 平台结合 Flask-RESTx 框架&#xff0c…

作者头像 李华
网站建设 2026/1/8 12:01:00

如何用6层网络让模糊动漫秒变4K壁纸?轻量级AI超分实战指南

还在为模糊的动漫截图发愁吗&#xff1f;想要把珍藏的老番截图变成高清壁纸却无从下手&#xff1f;今天&#xff0c;我们将带你解锁一个仅需6层网络的轻量级AI超分辨率神器&#xff0c;让你的动漫图片实现4倍无损放大&#xff01; 【免费下载链接】Real-ESRGAN Real-ESRGAN aim…

作者头像 李华
网站建设 2026/1/9 3:29:25

GLM-4.6V-Flash-WEB在社交媒体内容分析中的价值体现

GLM-4.6V-Flash-WEB在社交媒体内容分析中的价值体现 在微博热搜瞬息万变、小红书图文铺天盖地的今天&#xff0c;每天有数亿条带图动态被发布。一条“这届年轻人已经不想结婚了”的配图帖子&#xff0c;可能包含表情包、手写文字截图和模糊的生活照&#xff1b;一段短视频封面写…

作者头像 李华
网站建设 2026/1/8 17:38:39

Obfuscar混淆工具:保护.NET代码的终极解决方案

Obfuscar混淆工具&#xff1a;保护.NET代码的终极解决方案 【免费下载链接】obfuscar Open source obfuscation tool for .NET assemblies 项目地址: https://gitcode.com/gh_mirrors/ob/obfuscar 想要保护你的.NET应用程序不被反编译&#xff1f;Obfuscar混淆工具正是你…

作者头像 李华
网站建设 2026/1/6 20:13:03

Dify凭证管理完全手册(涵盖密钥轮换与权限隔离最佳实践)

第一章&#xff1a;Dify凭证管理概述Dify 是一个融合了低代码与 AI 能力的应用开发平台&#xff0c;支持用户通过可视化界面和编程方式构建智能应用。在实际使用过程中&#xff0c;系统需要与多种外部服务&#xff08;如数据库、API 网关、云存储等&#xff09;进行交互&#x…

作者头像 李华