文章目录

  • 前言
  • 一、UIViewController 生命周期有关函数
  • 二、UIViewController 中函数的执行顺序
    • 运行结果
      • 1.present和dismiss
      • 2.push和pop
  • 三、总结

前言

UIViewController 是在 iOS 开发中一个非常重要的角色,他是 view 和 model 的桥梁,通过 UIViewController 的管理将数据展示在视图上。与此同时作为 uikit 中最基本的一个类,一般复杂的项目都离不开 UIViewController 作为基类,所以了解 UIViewController 的生命周期是很重要的。

一、UIViewController 生命周期有关函数

下图是 UIViewController 生命周期方法的调用函数

请添加图片描述

二、UIViewController 中函数的执行顺序

下面我会给出代码这段代码是将两个视图之间进行转换,同时打印相关的函数名来观察他的生命周期。在这里我给了两种方式来展示出他的转换,一个是 push 一个是 present。

#import "ViewControllerA.h"
#import "ViewControllerB.h"
@interface ViewControllerA ()
@property (nonatomic, strong) UIButton *btn1;
@property (nonatomic, strong) UIButton *btn2;
@end@implementation ViewControllerA- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor blueColor];_btn1 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn1 setTitle:@"next_view" forState:UIControlStateNormal];_btn1.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 - 50, 200, 100);[self.view addSubview:_btn1];[_btn1 addTarget:self action:@selector(Next_present) forControlEvents:UIControlEventTouchUpInside];_btn2 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn2 setTitle:@"next_view" forState:UIControlStateNormal];_btn2.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 + 150, 200, 100);[self.view addSubview:_btn2];[_btn2 addTarget:self action:@selector(Next_push) forControlEvents:UIControlEventTouchUpInside];NSLog(@"%s", __func__);
}
- (void) Next_present {ViewControllerB *b = [[ViewControllerB alloc] init];NSLog(@"--------a->b---------");b.modalPresentationStyle = UIModalPresentationFullScreen;[self presentViewController:b animated:YES completion:nil];
}
- (void) Next_push {ViewControllerB *b = [[ViewControllerB alloc] init];NSLog(@"--------a->b---------");[self.navigationController pushViewController:b animated:YES];
}
- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewWillLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {NSLog(@"%s",__func__);
}
- (void)viewWillDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewDidDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end
#import "ViewControllerB.h"
#import "ViewControllerA.h"
@interface ViewControllerB ()
@property (nonatomic, strong) UIButton *btn1;
@property (nonatomic, strong) UIButton *btn2;
@end@implementation ViewControllerB- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor redColor];_btn1 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn1 setTitle:@"next_dismiss" forState:UIControlStateNormal];_btn1.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 - 50, 200, 100);[self.view addSubview:_btn1];[_btn1 addTarget:self action:@selector(Next_dismiss) forControlEvents:UIControlEventTouchUpInside];_btn2 = [UIButton buttonWithType:UIButtonTypeSystem];[_btn2 setTitle:@"next_pop" forState:UIControlStateNormal];_btn2.frame = CGRectMake(self.view.frame.size.width / 2 - 50, self.view.frame.size.height / 2 + 150, 200, 100);[self.view addSubview:_btn2];[_btn2 addTarget:self action:@selector(Next_pop) forControlEvents:UIControlEventTouchUpInside];NSLog(@"%s", __func__);
}
- (void) Next_dismiss {NSLog(@"--------b->a---------");[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) Next_pop {NSLog(@"--------b->a---------");[self.navigationController popViewControllerAnimated:YES];
}
- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}
- (void)viewWillAppear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewWillLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidLayoutSubviews {NSLog(@"%s", __func__);
}
- (void)viewDidAppear:(BOOL)animated {NSLog(@"%s",__func__);
}
- (void)viewWillDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
- (void)viewDidDisappear:(BOOL)animated {NSLog(@"%s", __func__);
}
/*
#pragma mark - Navigation// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {// Get the new view controller using [segue destinationViewController].// Pass the selected object to the new view controller.
}
*/@end

运行结果

1.present和dismiss

请添加图片描述

下面是函数打印的结果

请添加图片描述

在这里就是这样一个顺序,就是先执行loadview这一步把View载入到内存中,然后再用viewDidload这个方法把控件加载到view上,然后就是调用viewwilllayoutsubviewviewdidlayoutsubview这两个方法来进行布局,最后会执行 viewdidappear 这个方法完成所有视图的加载。

这是弹出的部分,在后面我们把 push 和 pop 这一对展示完后我会去结合 present 和 dismis解释视图消失相关的内容。

2.push和pop

请添加图片描述

代码和上面相同

下面是打印结果

请添加图片描述

在这里我去着重介绍一下他的消失顺序,push 和 pop 的消失与 present 和 dismiss 的消失最大的不同就是push 中的 viewDidDisappear 是在下一个视图的 viewDidAppear 之前的然而你像在 present 中 viewDidDisappear是在下一个视图 viewDidAppear 之后的。

在这里最重要的原因就是

  • 因为 push 是栈结构,A 被“挤下去”,所以它会走消失的生命周期。
  • B 被放在最顶上,执行“将要出现”和“已经出现”。
  • present 时,B 的 didAppear 在 A 的 didDisappear 之前执行
  • 也就是说,新控制器(B)已经展示成功了,旧控制器(A)才真正被认为消失。
  • 这是因为 present 是模态展示,A 并没有被销毁,只是被 B 遮挡了,系统优先保证 B 先可见。

三、总结

init / loadView -> viewDidLoad -> viewWillAppear -> viewDidAppear
-> viewWillDisappear -> viewDidDisappear -> dealloc

这就是一个非常简单的流程图他也展示了UIViewController 的生命周期。

在这里我想补充一点就是

- (void)loadView {[super loadView];NSLog(@"%s", __func__);
}

在这之中我们必须要使用**[super loadView]**因为这样他就可以帮助我们自动生成 View。如果我们找不到 View,程序就会一直调用loadView方法来寻找。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98796.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98796.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/98796.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第30章 零售与电商AI应用

本章将深入探讨人工智能在零售与电商领域的革命性应用。我们将从智能推荐系统、动态定价、库存管理到创新的虚拟试衣间,全面解析AI如何重塑购物体验和商业运营效率,并为每个关键技术点提供代码实战,帮助你掌握将AI应用于真实商业场景的能力。…

QT通过QModbusRtuSerialMaster读写电子秤数据实例

一、电子称常用功能:称重、清零、去皮;电子秤的通讯方式:Modbus通信、串口通信。二、QT读写电子秤软件界面如下:三、核心代码如下:.pro项目文件代码:QT core gui serialbus serialport.h头文件代码#…

sqlmap常用命令

ZZHow(ZZHow1024) 一、扫描注入点 1.GET方法,给URL: #探测该url是否存在漏洞 python sqlmap.py -u "http://192.168.10.1/sqli/Less-1/?id1"#如果我们已经知道admin这里是注入点的话,可以在其后面加个*来让sqlmap对其注入 python …

JVM如何排查OOM

当JVM(Java虚拟机)出现OOM(OutOfMemoryError)时,可以按照以下步骤和方法,用于帮助定位和解决JVM中的OOM问题1.查看异常堆栈信息查看异常堆栈信息(StackTrace)是定位问题的关键。OOM异…

存算一体芯片生态评估:从三星PIM到知存科技WTM2101

点击 “AladdinEdu,同学们用得起的【H卡】算力平台”,注册即送-H卡级别算力,80G大显存,按量计费,灵活弹性,顶级配置,学生更享专属优惠。 引言:存算一体技术的崛起与意义 在传统冯诺…

[数据结构] 栈 · Stack

一.栈 stack 1.概念 栈 : 一种特殊的线性表 , 其只允许再固定的一段进行插入和删除元素操作 进行数据插入和删除操作的一段称为 栈顶 ; 另一端称为栈底栈中的数据元素遵循 先进后出 原则(LIFO)压栈 : 栈的插入操作叫做 进栈 或 压栈 或 入栈 , 入数据在栈顶出栈 : 栈的删除…

MySQL执行过程中如何选择最佳的执行路径

本篇文章介绍一个非常核心的数据库问题。MySQL 选择最佳执行路径(即“查询优化”)的过程是由其查询优化器(Query Optimizer) 完成的。 简单来说,优化器的目标是:在多种可能的执行方案中,选择一个…

【设计模式】从游戏角度开始了解设计模式 --- 抽象工厂模式

永远记住,你的存在是有意义的, 你很重要, 你是被爱着的, 而且你为这个世界带来了无可取代的东西。 -- 麦克西 《男孩、鼹鼠、狐狸和马》-- 从零开始了解设计模式抽象工厂模式抽象工厂模式 今天我们一起来探究抽象工厂模式&#x…

tensorflow.js 使用场景

TensorFlow.js (简称 TF.js) 是一个利用 WebGL 和 Node.js 在浏览器和服务器端进行机器学习模型训练和部署(推理)的 JavaScript 库。它的核心价值在于将机器学习的能力带入了 Web 开发者和 JavaScript 生态的领域。 其主要应用场景可以分为以下几大类: 一、在浏览器中直接进…

详解mcp以及agen架构设计与实现

文章目录1.MCP概念2.MCP服务端主要能力3.MCP技术生态4.MCP与Function call区别5.MCP生命周期6.MCP java SDK7.MCP应用场景8.基于springAIollma阿里qianwenmcp设计私有AIAgent应用实现9.AI java项目落地技术选型10.构建AI Agent四大模块11.LLM(大模型)与MCP之间关系12.A2A、MCP、…

六级第一关——下楼梯

上目录: 目录 题目描述 输入格式 输出格式 输入输出样例 说明/提示 一、DP的意义以及线性动规简介 在一个困难的嵌套决策链中,决策出最优解。 二、动态规划性质浅谈 三、子序列问题 (一)一个序列中的最长上升子序列&am…

【Linux基础】Linux系统配置IP详解:从入门到精通

目录 1 Linux网络配置概述 2 网卡配置文件位置和命名规则 2.1 配置文件位置 2.2 网卡命名规则 2.3 配置文件命名示例 3 网卡配置文件详解 3.1 主要参数说明 4 Linux系统配置IP步骤 4.1 DHCP动态配置 4.2 静态IP配置 5 Linux网络配置流程 5.1 网络配置流程 5.2 网卡…

C语言sprintf的高效替代方案

C语言的sprintf和snprintf将变量格式化输出到内存buffer,其功能强大,用起来很方便。但sprintf系列函数的运行效率低下,主要包括四方面的原因:格式字符串解析、变参处理、locale(本地化)支持和通用&#xff…

【知识堂】制造业与物流数字化全景图:系统缩写大全与专业名词速查手册

前言在制造业和物流行业的数字化转型过程中,我们经常会接触到大量的 系统缩写(如 ERP、MES、WMS…)和 专业名词(如 AGV、BOM、LOT…)。 这些缩写往往让刚入行的人“一头雾水”,即使是有经验的从业者&#x…

利用JSONCrack与cpolar提升数据可视化及跨团队协作效率

文章目录前言1. 在Linux上使用Docker安装JSONCrack2. 安装Cpolar内网穿透工具3. 配置JSON Crack界面公网地址4. 远程访问 JSONCrack 界面5. 固定 JSONCrack公网地址前言 JSONCrack 是一款功能强大的开源数据可视化工具,专为解析和展示复杂的 JSON、XML 等结构化数据…

CANoe入门之一 CANoe功能概述

01 CANoe功能概述 CANoe软件在汽车电子领域被广泛应用。 CANoe软件的全称是CAN Open Environment,它是一个专业的系统级总线和ECU仿真、分析、开发、测试工具。支持ECU或总线网络开发从需求分析到系统实现的全过程,包括模型创建、仿真、测试、诊断及通信…

项目管理核心八项(软件篇)

2025年09月11日23:50:33:进来常思,写代码也五六年了,后面的路该何去何从呢? 项目管理核心八项一、项目管理之“建立开发人员 backup 机制”二、待补充一、项目管理之“建立开发人员 backup 机制” “建立开发人员 backup 机制” 是…

springboot redisson 分布式锁入门与实战

Spring Boot3 Redisson 项目地址 https://gitee.com/supervol/loong-springboot-study (记得给个start,感谢) Redisson 介绍 在分布式系统中,多节点部署的应用对共享资源(如数据库记录、缓存键、文件)的…

使用 Tkinter + Requests 实现地理信息安全系统学习时长助手

✨重磅!盹猫的个人小站正式上线啦~诚邀各位技术大佬前来探秘!✨ 这里有: 硬核技术干货:编程技巧、开发经验、踩坑指南,带你解锁技术新姿势!趣味开发日常:代码背后的脑洞故事、工具…

构建一个优雅的待办事项应用:现代JavaScript实践

构建一个优雅的待办事项应用:现代JavaScript实践本文将介绍如何使用现代JavaScript(ES6)和DOM操作创建一个功能完整的待办事项应用,无需任何外部库或框架。功能概述添加新任务标记任务为完成/未完成编辑任务内容删除任务过滤任务&…