news 2026/4/15 15:02:38

如何在iOS中使用UIViewController的生命周期方法?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何在iOS中使用UIViewController的生命周期方法?

一、核心原则(先记牢)

  1. 所有生命周期方法都要先调用父类的实现(比如[super viewDidLoad]),且通常放在方法第一行。
  2. 不要手动调用生命周期方法(比如不要自己写[self viewDidAppear:YES]),由系统自动触发。
  3. 按「初始化→视图加载→显示→布局→消失→销毁」的逻辑分配代码,避免功能混乱。

二、分场景使用(附完整示例)

下面是一个贴近实际开发的UIViewController示例,标注了每个生命周期方法的典型用法:

objective-c

#import <UIKit/UIKit.h> @interface DemoViewController : UIViewController // 定义需要管理的资源(定时器、监听、网络请求等) @property (nonatomic, strong) NSTimer *updateTimer; @property (nonatomic, strong) NSURLSessionDataTask *dataTask; @end @implementation DemoViewController // 1. 初始化:仅做数据/属性初始化,不创建UI - (instancetype)initWithTitle:(NSString *)title { self = [super init]; if (self) { // 初始化业务数据、配置项 self.title = title ?: @"默认标题"; NSLog(@"1. 初始化:仅初始化数据,不创建UI"); } return self; } // 2. 视图加载完成:一次性创建UI、绑定数据(仅调用一次) - (void)viewDidLoad { [super viewDidLoad]; // 必须先调父类 NSLog(@"2. 视图加载完成:创建UI、初始化一次性资源"); // ✅ 典型用法1:设置视图基础样式 self.view.backgroundColor = [UIColor whiteColor]; // ✅ 典型用法2:创建UI控件并添加到视图 UIButton *testBtn = [UIButton buttonWithType:UIButtonTypeSystem]; testBtn.frame = CGRectMake(100, 200, 200, 50); [testBtn setTitle:self.title forState:UIControlStateNormal]; [testBtn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:testBtn]; // ✅ 典型用法3:初始化网络请求(仅发起一次的请求,比如获取页面基础数据) [self loadBaseData]; } // 3. 视图即将显示:每次显示都要做的操作(比如刷新数据、开启监听) - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; // 必须先调父类 NSLog(@"3. 视图即将显示:刷新数据、开启定时器/监听"); // ✅ 典型用法1:刷新页面数据(比如从其他页面返回后更新) [self refreshPageData]; // ✅ 典型用法2:开启定时器/通知监听 self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction) userInfo:nil repeats:YES]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"TestNotification" object:nil]; // ✅ 典型用法3:设置导航栏/状态栏样式 self.navigationController.navigationBar.tintColor = [UIColor blueColor]; } // 4. 视图布局:调整控件位置(适配屏幕旋转、尺寸变化) - (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; NSLog(@"4. 视图即将布局:调整控件frame(可选)"); // ✅ 典型用法:手动调整控件布局(比如适配不同屏幕尺寸) UIButton *testBtn = self.view.subviews.firstObject; testBtn.centerXAnchor.constraintEqualToAnchor:self.view.centerXAnchor.active = YES; // 自动布局示例 } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; NSLog(@"5. 视图布局完成:获取控件最终尺寸"); // ✅ 典型用法:获取控件最终的frame/size(比如ScrollView的contentSize) UIButton *testBtn = self.view.subviews.firstObject; NSLog(@"按钮最终尺寸:%@", NSStringFromCGRect(testBtn.frame)); } // 5. 视图已经显示:执行动画、请求权限(需要视图可见时操作) - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"6. 视图已经显示:执行动画、请求权限"); // ✅ 典型用法1:执行视图动画 UIButton *testBtn = self.view.subviews.firstObject; [UIView animateWithDuration:0.5 animations:^{ testBtn.transform = CGAffineTransformMakeScale(1.1, 1.1); }]; // ✅ 典型用法2:请求权限(比如定位、相册,需要视图可见时弹框) [self requestPhotoPermission]; } // 6. 视图即将消失:清理临时资源(关闭定时器、移除监听) - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; NSLog(@"7. 视图即将消失:关闭定时器、移除监听"); // ✅ 典型用法1:停止定时器 [self.updateTimer invalidate]; self.updateTimer = nil; // 置空避免野指针 // ✅ 典型用法2:移除通知监听 [[NSNotificationCenter defaultCenter] removeObserver:self]; // ✅ 典型用法3:取消未完成的网络请求 [self.dataTask cancel]; self.dataTask = nil; // ✅ 典型用法4:隐藏键盘 [self.view endEditing:YES]; } // 7. 视图已经消失:释放非必要资源(比如缓存、临时文件) - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; NSLog(@"8. 视图已经消失:释放临时资源"); // ✅ 典型用法:清理内存缓存 [[NSURLCache sharedURLCache] removeAllCachedResponses]; } // 8. 内存警告:释放非核心资源(避免APP崩溃) - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; NSLog(@"9. 内存警告:释放非必要资源"); // ✅ 典型用法:释放图片缓存、非当前显示的数据 [[SDImageCache sharedImageCache] clearMemory]; // 第三方图片缓存示例 self.dataTask = nil; // 取消网络请求 } // 9. 销毁:最终清理(移除所有强引用、避免内存泄漏) - (void)dealloc { NSLog(@"10. 控制器销毁:最终清理资源"); // ✅ 典型用法:最后兜底清理(比如确认定时器/监听已移除) [self.updateTimer invalidate]; [[NSNotificationCenter defaultCenter] removeObserver:self]; } // --------------- 辅助方法(业务逻辑)--------------- - (void)loadBaseData { // 初始化页面基础数据(仅调用一次) self.dataTask = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://example.com/baseData"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 处理数据... }]; [self.dataTask resume]; } - (void)refreshPageData { // 每次显示页面都刷新数据 NSLog(@"刷新页面数据"); } - (void)timerAction { // 定时器回调 NSLog(@"定时器执行:更新页面状态"); } - (void)handleNotification:(NSNotification *)notification { // 通知监听回调 } - (void)requestPhotoPermission { // 请求相册权限 [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { // 处理权限结果... }]; } - (void)btnClick { NSLog(@"按钮点击"); } @end

三、常见错误(避坑指南)

  1. ❌ 不在viewDidLoad里创建 UI,反而在init里创建:init阶段self.view还未加载,创建的 UI 无法添加到视图,会导致控件不显示。
  2. ❌ 忘记调用super的生命周期方法:比如- (void)viewDidLoad { /* 没写[super viewDidLoad] */ },会导致系统默认逻辑失效(比如视图无法正常加载)。
  3. ❌ 在viewWillAppear:里创建 UI:每次页面显示都会重复创建控件,导致内存泄漏、控件叠加。
  4. ❌ 没有在viewWillDisappear:里停止定时器 / 移除监听:控制器销毁后定时器仍在运行,会导致野指针崩溃(经典内存泄漏场景)。

四、Swift 版本简化示例(适配 Swift 开发者)

如果用 Swift 开发,核心逻辑一致,语法稍有不同:

swift

import UIKit class DemoViewController: UIViewController { var updateTimer: Timer? var dataTask: URLSessionDataTask? override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) self.title = "默认标题" } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 创建UI... } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateTimer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) updateTimer?.invalidate() updateTimer = nil dataTask?.cancel() dataTask = nil } @objc func timerAction() { print("定时器执行") } deinit { print("控制器销毁") } }

总结

  1. 分工明确viewDidLoad做「一次性初始化(UI / 基础数据)」,viewWillAppear:做「每次显示都要刷新的操作」,viewWillDisappear:做「资源清理」。
  2. 资源闭环:开启的资源(定时器、监听、网络请求)必须在对应阶段关闭,避免内存泄漏。
  3. 遵循规范:必调父类方法、不手动触发生命周期方法,是避免崩溃的核心。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 10:15:08

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

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

作者头像 李华
网站建设 2026/4/10 16:39:20

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

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

作者头像 李华
网站建设 2026/3/31 3:56:10

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

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

作者头像 李华
网站建设 2026/4/10 16:38:03

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

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

作者头像 李华
网站建设 2026/4/3 7:37:23

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

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

作者头像 李华