news 2026/6/15 17:16:07

如何在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/6/15 13:09:52

大语言模型的“涌现”之谜:能力还是智能?

导语&#xff1a;涌现&#xff08;Emergence&#xff09;是复杂科学中的核心概念&#xff0c;用以描述多体系统如何在规模扩展后呈现出全新的宏观属性——这些属性可以由低维的有效变量与理论加以刻画&#xff0c;而无需逐一追踪微观机制&#xff0c;这正是安德森所说的“多者异…

作者头像 李华
网站建设 2026/4/30 6:30:59

GLM-4.6V-Flash-WEB在食品包装识别中的准确性验证

GLM-4.6V-Flash-WEB在食品包装识别中的准确性验证 在智能消费服务日益普及的今天&#xff0c;用户不再满足于“拍图识物”式的简单图像分类。当一位消费者举起手机拍摄一盒进口饼干&#xff0c;他真正关心的是&#xff1a;“这东西有没有反式脂肪&#xff1f;”“适合乳糖不耐人…

作者头像 李华
网站建设 2026/6/15 13:08:55

AppSync Unified:iOS签名绕过技术完全解析

想要在越狱设备上突破苹果应用安装限制吗&#xff1f;AppSync Unified作为iOS生态中最成熟的签名验证绕过工具&#xff0c;为开发者和用户提供了前所未有的应用部署自由。本文将深入探讨这一革命性技术的实现原理、部署方法以及实际应用价值。 【免费下载链接】AppSync Unified…

作者头像 李华
网站建设 2026/6/15 1:29:09

FabricMC模组加载器终极完整指南:从零开始构建个性化游戏世界

FabricMC模组加载器终极完整指南&#xff1a;从零开始构建个性化游戏世界 【免费下载链接】fabric-loader Fabrics mostly-version-independent mod loader. 项目地址: https://gitcode.com/gh_mirrors/fa/fabric-loader FabricMC模组加载器是一款专为Minecraft游戏设计…

作者头像 李华
网站建设 2026/6/15 12:14:34

Obsidian插件汉化:3步让英文界面秒变中文

Obsidian插件汉化&#xff1a;3步让英文界面秒变中文 【免费下载链接】obsidian-i18n 项目地址: https://gitcode.com/gh_mirrors/ob/obsidian-i18n 还在为Obsidian插件的英文界面而烦恼吗&#xff1f;想要一键实现所有插件的完美中文显示&#xff1f;今天我要分享一个…

作者头像 李华