【iOS】UIViewController的生命周期
UIViewController的生命周期
文章目录
- UIViewController的生命周期
- 前言
- UIViewController的一个结构
- UIViewController的函数的执行顺序
- 运行代码
- viewWillAppear && viewDidAppear
- 多个视图控制器跳转时的生命周期
- push
- present
- 小结
前言
之前对于有关于UIViewControlller的理解比较浅显,仅仅只知道他是用来加载视图的,后面在有关天气预报的内容中了解了有关视图控制器生命周期的内容。
UIViewController的一个结构
UIViewController这个视图控制器
UIViewController的函数的执行顺序
这里先给出一个图片来展示一下流程,然后我们在通过讲解一下相关的内容,这里我们尝试在打印所有的内容。

这里笔者想通过两个视图控制之间相互切换来实现一个展示每一个视图控制器生命周期的效果,这里我们先讨论有关于
loadView这个函数开始的一些执行过程。
这里我们先要重写有关ViewController的生命周期中所有函数,让他先可以打印自己的函数名。
//
// FirsttViewController.m
// ViewController的生命周期
//
// Created by nanxun on 2024/9/9.
//#import "FirsttViewController.h"
#import "TestViewController.h"
@interface FirsttViewController ()@end@implementation FirsttViewController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.whiteColor;UIView* myView = [[UIView alloc] initWithFrame:CGRectMake(80, 80, 80, 80)];myView.backgroundColor = UIColor.redColor;[self.view addSubview:myView];UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];btn.frame = CGRectMake(200, 200, 50, 50);btn.backgroundColor = UIColor.redColor;[self.view addSubview:btn];[btn addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];NSLog(@"%s", __func__);// Do any additional setup after loading the view.
}
-(void)loadView {[super loadView];//注意这里重写子类方法的时候记得要先调用父类方法NSLog(@"%s", __func__);
}
-(void)press {TestViewController* vc =[[TestViewController alloc] init];[self.navigationController pushViewController:vc animated:YES];
}
-(void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];NSLog(@"%s", __func__);
}
-(void)viewDidAppear:(BOOL)animated {[super viewDidAppear:animated];NSLog(@"%s", __func__);
}
-(void)viewWillLayoutSubviews {[super viewWillLayoutSubviews];NSLog(@"%s", __func__);
}
-(void)viewDidLayoutSubviews {[super viewDidLayoutSubviews];NSLog(@"%s", __func__);
}
-(void)viewWillDisappear:(BOOL)animated {[super viewWillDisappear:animated];NSLog(@"%s", __func__);
}
-(void)viewDidDisappear:(BOOL)animated {[super viewDidDisappear:animated];NSLog(@"%s", __func__);
}
- (void)dealloc {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
运行代码
这里我们通过打断点的方式给每一个ViewController的方法都打上断点,然后我们先加载第一个视图控制器

这里可以看到我们的代码是这样一个执行流程:先执行loadView这一步是将view载入到内存中,然后我们在viewDidLoad这个方法中把相关的控件加载到我们的view上,再执行ViewWillAppear这个方法,后面会调用ViewWillLayoutSubview这个方法,然后就会把视图布局好,然后执行ViewDidLayoutSubview这个方法然后我们就会执行ViewDidAppear这个方法来完成我们的所有视图的加载。

这时候我们通过点击我们的按钮然后我们这里可以看到两个视图控制器,从前一个视图控制器转移到后面的视图控制器的过程并不是前一个视图控制器直接执行viewWillDisAppear而是后一个视图控制器先执行viewDidLoad这个方法加载好控件之后前一个视图控制开始执行有关消失的方法,后一个视图控制器开始执行有关视图出现的函数,这样个流程才实现一个视图控制器的完整的生命周期,下面我给出打印的内容。

后面的视图控制器出现在屏幕上,和前一个视图控制器的view消失是一个交替的过程,这里可以看到我们的第一个视图控制器并没有被释放,没有执行有关视图控制器销毁的函数,但是当我们从后面的一个视图控制器跳转到前一个视图控制器的时候,后面的视图会执行一个dealloc的销毁函数,这里指的是视图控制器的销毁。

这里笔者简单讲述分析一下每一个视图控制器调用的函数的相关作用:(引用自UIViewController的生命周期)
- 1、
initWithCoder:或initWithNibName:Bundle首先从归档文件中加载UIViewController对象。即使是纯代码,也会把nil作为参数传给后者。- 2、
awakeFromNib作为第一个方法的助手,方法处理一些额外的设置- 3、
loadView创建或加载一个view并把它赋值给UIViewController的view属性- 4、
viewDidLoad此时整个视图层次(view hierarchy)已经放到内存中,可以移除一些视图,修改约束,加载数据等- 5、
viewWillAppear视图加载完成,并即将显示在屏幕上。还没设置动画,可以改变当前屏幕方向或状态栏的风格等- 6、
viewWillLayoutSubviews即将开始子视图位置布局- 7、
viewDidLayoutSubviews用于通知视图的位置布局已经完成- 8、
viewDidAppear视图已经展示在屏幕上,可以对视图做一些关于展示效果方面的修改。- 9、
viewWillDisappear视图即将消失- 10、
viewDidDisappear视图已经消失- 11、
dealloc视图销毁的时候调用
笔者这里补充一下有关于前三个函数内容理解:

-
这里可以看到我么的第一步创建方式如果是代码的方式他会执行
initWithNibName:Bundle这个方法,我们因为是通过纯代码方式创建的,会将nil作为一个参数传到后者。我们的另一种则是通过故事板来创建。 -
当
awakeFromNib方法被调用时,所有视图的outlet和action已经连接,但还没有被确定,这个方法可以算作适合视图控制器的实例化配合一起使用的,因为有些需要根据用户喜好来进行设置的内容,无法存在storyBoard或xib中,所以可以在awakeFromNib方法中被加载进来。 -
loadView这个方法中,要正式加载View了。首先我们得知道,控制器 view 是通过懒加载的方式进行加载的,即用到的时候再加载。永远不要主动调用这个方法。当我们用到控制器 view 时,就会调用控制器 view 的 get 方法,在 get 方法内部,首先判断 view 是否已经创建,如果已存在,则直接返回存在的 view,如果不存在,则调用控制器的 loadView 方法,在控制器没有被销毁的情况下,loadView 也可能会被执行多次。- 这里提到了如果不存在view的话他会执行多次
loadView这里可能会出现一个死循环,也就是说我们在重写的loadView方法中没有创建view这里就会出现一个死循环的问题 - 对于是否要调用
super loadView这个语句的话,并把子类的 view 赋给 view 属性 (property) (你 create 的 view 必须是唯一的实例,并且不被其他任何 controller 共享)。 **如果你要进行进一步初始化你的 views,你应该在 viewDidLoad 函数中去做。**在实际上我们如果想重写这个方法的时候也是要设置一个不同的子类view,而如果调用的是super loadView这个语句的话,他只会返回一个空白的View,在开发的角度来说没有什么意义,笔者这里仅仅只是为了展示UIViewController的一个生命周期才调用上述的这个方法。
这里有图可以很好的展示相关的内容:

- 这里提到了如果不存在view的话他会执行多次
viewWillAppear && viewDidAppear
- viewWillAppear:在系统载入视图的时候,会调用这个方法,我们可以在这个方法中对将要显示的视图再进一步的设置,同时调用数据要更新的时候,都在这个方法里面实现。
- viewDidAppear: 在view被添加到视图层级中以及多视图,上下级视图切换时调用这个方法,在这里可以对正在显示的视图做进一步的设置。
视图层次(view hierachy)因为每个视图都有自己的子视图,这个视图层次其实也可以理解为一颗树状的数据结构。而树的根节点,也就是
根视图(root view),在UIViewController中以view属性。它可以看做是其他所有子视图的容器,也就是根节点。
多个视图控制器跳转时的生命周期
push
当我们点击 push 的时候首先会加载下一个界面然后才会调用界面的消失方法。
- init:ViewController2
- loadView:ViewController2
- viewDidLoad:ViewController2
- viewWillDisappear:ViewController1 将要消失
- viewWillAppear:ViewController2 将要出现
- viewWillLayoutSubviews ViewController2
- viewDidLayoutSubviews ViewController2
- viewWillLayoutSubviews:ViewController1
- viewDidLayoutSubviews:ViewController1
- viewDidDisappear:ViewController1 完全消失
- viewDidAppear:ViewController2 完全出现
上面的图片也展示出了这个过程。

push会调用我们的viewDidDisappear方法
present
但是present方法和push调用的视图控制器的流程是不一样的:

这里发现我们的present方法并不会让我们的前一个视图控制器调用viewWillAppear和viewDidAppear这两个方法,同时也不会调用有关于viewDidDisappear和viewWillDisAppear
小结
笔者对于UIViewController的生命周期有了一点简单的认识,后面会讲一下这里push和present两个方法具体区别。
参考博客
UIViewController的生命周期
相关文章:
【iOS】UIViewController的生命周期
UIViewController的生命周期 文章目录 UIViewController的生命周期前言UIViewController的一个结构UIViewController的函数的执行顺序运行代码viewWillAppear && viewDidAppear多个视图控制器跳转时的生命周期pushpresent 小结 前言 之前对于有关于UIViewControlller的…...
ELK在Linux服务器下使用docker快速部署(超详细)
ELK是什么? 首先说说什么是ELK ELK 是一个开源的日志管理和分析平台,由三个主要组件组成: Elasticsearch:一个分布式搜索和分析引擎,能够快速存储、搜索和分析大量数据。它是 ELK 堆栈的核心,负责数据的…...
unity导入半透明webm + AE合成半透明视频
有些webm的文件导入unity后无法正常播报,踩坑好久才知道需要webm中的:VP8 标准 现在手上有几条mp4双通道的视频,当然unity中有插件是可以支持这种视频的,为了省事和代码洁癖,毅然决然要webm走到黑。 mp4导入AE合成半透…...
力扣: 四数相加II
文章目录 需求代码结尾 需求 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 示例 1: 输入…...
径向基函数神经网络RBFNN案例实操
简介 (来自ChatGPT的介绍,如有更正建议请指出) 径向基函数神经网络(Radial Basis Function Neural Network, RBFNN)是一种特殊的前馈神经网络,其结构和特点与其他常见的神经网络有所不同,主要表现在以下几个方面: 网络结构三层结构:RBF神经网络通常由三层组成:输入层…...
Java-数据结构-二叉树-习题(一) (✪ω✪)
文本目录: ❄️一、习题一(检查两颗树是否相同): ▶ 思路: ▶ 代码: ❄️二、习题二(另一棵树的子树): ▶ 思路: ▶ 代码: ❄️三、习题三(翻转二叉树): ▶ 思路: ▶ 代…...
js 时间戳转日期格式
timestampToDate(obj.project_time), import moment from “moment”; const timestampToDate (timestamp: any) > { const date new Date(timestamp * 1000); const newDate moment(date).format(“YYYY-MM-DD”); return newDate; // 使用Intl.DateTimeFormat进行格式…...
基于人工智能的自动驾驶系统项目教学指南
自动驾驶系统是人工智能的一个核心应用领域,涉及多个学科的交叉:从计算机视觉、深度学习、传感器融合到控制系统,自动驾驶项目可以提供高度的挑战性和实践意义。在这篇文章中,我们将构建一个基于深度学习的自动驾驶系统的简化版本…...
[Linux#49][UDP] 2w字详解 | socketaddr | 常用API | 实操:实现简易Udp传输
目录 套接字地址结构(sockaddr) 1.Socket API 2.sockaddr结构 3. sockaddr、sockaddr_in 和 sockaddr_un 的关系 sockaddr 结构体 sockaddr_in 结构体(IPv4 套接字地址) sockaddr_un 结构体(Unix域套接字地址&a…...
期权组合策略有什么风险?期权组合策略是什么?
今天期权懂带你了解期权组合策略有什么风险?期权组合策略是什么?期权组合策略是通过结合不同期权合约(如看涨期权和看跌期权),以及标的资产(如股票)来实现特定投资目标的策略。 期权组合策略市…...
从Zotero6到Zotero7的数据迁移尝试?(有错勿喷,多多指教!)
从Zotero6到Zotero7的数据迁移尝试 0 前言 之前在主机上一直用的Zotero6(实验室主机),最近发现在个人笔记本上看论文更频繁,尝试重新部署Zotero,才发现竟然更新了!所以这里简单记录一下数据迁移过程&…...
快速排序(分治思想)
什么是快速排序 快速排序(Quick Sort)是一种广泛使用的高效排序算法,由计算机科学家托尼霍尔在1960年提出。它采用分治法(Divide and Conquer)策略,将一个大数组分为两个小数组,然后递归地对这两…...
JAVA相关知识
JAVA基础知识 说一下对象创建的过程? 类加载检查:当Java虚拟机(JVM)遇到一个类的new指令时,它首先检查这个类是否已经被加载、链接和初始化。如果没有,JVM会通过类加载器(ClassLoaderÿ…...
详解TCP的三次握手
TCP(三次握手)是指在建立一个可靠的传输控制协议 (TCP) 连接时,客户端和服务器之间的三步交互过程。这个过程的主要目的是确保连接是可靠的、双方的发送与接收能力是正常的,并且可以开始数据传输。下面是对每个步骤的详细解释&…...
Java面试篇基础部分-Java创建线程详解
导语 多线程的方式能够在操作系统的多核配置上更好的利用服务器的多个CPU的资源,这样的操作可以使得程序运行起来更加高效。Java中多线程机制提供了在一个进程内并发去执行多个线程,并且每个线程都并行的去执行属于线程处理的自己的任务,这样可以提高程序的执行效率,让…...
Ubuntu 20.04/22.04无法连接网络(网络图标丢失、找不到网卡)的解决方案
问题复述: Ubuntu 20.04无法连接到网络,网络连接图标丢失,网络设置中无网络设置选项。 解决方案 对于Ubuntu 20.04而言:逐条执行 sudo service network-manager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo…...
《MDTv2- Masked Diffusion Transformer is a Strong Image Synthesizer》
论文摘要 论文提出了一种名为**Masked Diffusion Transformer (MDT)**的新模型,旨在增强扩散概率模型(DPMs)在图像合成中的上下文推理能力。通过引入掩码潜在建模方案,MDT能够显著提升DPMs在图像中对象部分之间关系的学习能力&am…...
算法 - 二分查找
算法 - 二分查找 今天继续八股文学习,看一下比较常规的几个算法 二分查找是一个基于分治策略的搜索方法,简单的理解就是每次都缩小一轮搜索范围,从中间search一次,直到搜索到结果或者为空为止。 基本思路(设一个有序的…...
Python知识点:如何使用Python进行图像批处理
在Python中进行图像批处理可以使用多种库,如 Pillow、OpenCV 和 imageio。这些库可以用来执行各种图像处理任务,如调整大小、裁剪、旋转、滤镜应用等。以下是使用这些库进行图像批处理的示例。 使用 Pillow 进行图像批处理 Pillow 是一个功能强大的图像…...
数据结构实验1
实验题1:求1到n的连续整数和 题目描述 编写一个程序,对于给定的正整数n,求12…十n,采用逐个累加与(n1)/2(高斯法)两种解法。对于相同的n,给出这两种解法的求和结果和求解时间,并用相关数据进行测试。 运行代码 //实验题1:求1到n的连续整数和 #includ…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
微信小程序云开发平台MySQL的连接方式
注:微信小程序云开发平台指的是腾讯云开发 先给结论:微信小程序云开发平台的MySQL,无法通过获取数据库连接信息的方式进行连接,连接只能通过云开发的SDK连接,具体要参考官方文档: 为什么? 因为…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
