当前位置: 首页 > news >正文

【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并把它赋值给UIViewControllerview属性
  • 4、viewDidLoad 此时整个视图层次(view hierarchy)已经放到内存中,可以移除一些视图,修改约束,加载数据等
  • 5、viewWillAppear 视图加载完成,并即将显示在屏幕上。还没设置动画,可以改变当前屏幕方向或状态栏的风格等
  • 6、viewWillLayoutSubviews即将开始子视图位置布局
  • 7、viewDidLayoutSubviews用于通知视图的位置布局已经完成
  • 8、viewDidAppear视图已经展示在屏幕上,可以对视图做一些关于展示效果方面的修改。
  • 9、viewWillDisappear视图即将消失
  • 10、viewDidDisappear视图已经消失
  • 11、dealloc视图销毁的时候调用

笔者这里补充一下有关于前三个函数内容理解:

在这里插入图片描述

  • 这里可以看到我么的第一步创建方式如果是代码的方式他会执行initWithNibName:Bundle这个方法,我们因为是通过纯代码方式创建的,会将nil作为一个参数传到后者。我们的另一种则是通过故事板来创建。

  • awakeFromNib方法被调用时,所有视图的outletaction已经连接,但还没有被确定,这个方法可以算作适合视图控制器的实例化配合一起使用的,因为有些需要根据用户喜好来进行设置的内容,无法存在storyBoardxib中,所以可以在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的一个生命周期才调用上述的这个方法。

    这里有图可以很好的展示相关的内容:

    在这里插入图片描述

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方法并不会让我们的前一个视图控制器调用viewWillAppearviewDidAppear这两个方法,同时也不会调用有关于viewDidDisappearviewWillDisAppear

小结

笔者对于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 &#xff0c;数组长度都是 n &#xff0c;请你计算有多少个元组 (i, j, k, l) 能满足&#xff1a; 0 < i, j, k, l < n nums1[i] nums2[j] nums3[k] nums4[l] 0 示例 1&#xff1a; 输入…...

径向基函数神经网络RBFNN案例实操

简介 (来自ChatGPT的介绍,如有更正建议请指出) 径向基函数神经网络(Radial Basis Function Neural Network, RBFNN)是一种特殊的前馈神经网络,其结构和特点与其他常见的神经网络有所不同,主要表现在以下几个方面: 网络结构三层结构:RBF神经网络通常由三层组成:输入层…...

Java-数据结构-二叉树-习题(一) (✪ω✪)

文本目录&#xff1a; ❄️一、习题一(检查两颗树是否相同)&#xff1a; ▶ 思路&#xff1a; ▶ 代码&#xff1a; ❄️二、习题二(另一棵树的子树)&#xff1a; ▶ 思路&#xff1a; ▶ 代码&#xff1a; ❄️三、习题三(翻转二叉树)&#xff1a; ▶ 思路&#xff1a; ▶ 代…...

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进行格式…...

基于人工智能的自动驾驶系统项目教学指南

自动驾驶系统是人工智能的一个核心应用领域&#xff0c;涉及多个学科的交叉&#xff1a;从计算机视觉、深度学习、传感器融合到控制系统&#xff0c;自动驾驶项目可以提供高度的挑战性和实践意义。在这篇文章中&#xff0c;我们将构建一个基于深度学习的自动驾驶系统的简化版本…...

[Linux#49][UDP] 2w字详解 | socketaddr | 常用API | 实操:实现简易Udp传输

目录 套接字地址结构&#xff08;sockaddr&#xff09; 1.Socket API 2.sockaddr结构 3. sockaddr、sockaddr_in 和 sockaddr_un 的关系 sockaddr 结构体 sockaddr_in 结构体&#xff08;IPv4 套接字地址&#xff09; sockaddr_un 结构体&#xff08;Unix域套接字地址&a…...

期权组合策略有什么风险?期权组合策略是什么?

今天期权懂带你了解期权组合策略有什么风险&#xff1f;期权组合策略是什么&#xff1f;期权组合策略是通过结合不同期权合约&#xff08;如看涨期权和看跌期权&#xff09;&#xff0c;以及标的资产&#xff08;如股票&#xff09;来实现特定投资目标的策略。 期权组合策略市…...

从Zotero6到Zotero7的数据迁移尝试?(有错勿喷,多多指教!)

从Zotero6到Zotero7的数据迁移尝试 0 前言 之前在主机上一直用的Zotero6&#xff08;实验室主机&#xff09;&#xff0c;最近发现在个人笔记本上看论文更频繁&#xff0c;尝试重新部署Zotero&#xff0c;才发现竟然更新了&#xff01;所以这里简单记录一下数据迁移过程&…...

快速排序(分治思想)

什么是快速排序 快速排序&#xff08;Quick Sort&#xff09;是一种广泛使用的高效排序算法&#xff0c;由计算机科学家托尼霍尔在1960年提出。它采用分治法&#xff08;Divide and Conquer&#xff09;策略&#xff0c;将一个大数组分为两个小数组&#xff0c;然后递归地对这两…...

JAVA相关知识

JAVA基础知识 说一下对象创建的过程&#xff1f; 类加载检查&#xff1a;当Java虚拟机&#xff08;JVM&#xff09;遇到一个类的new指令时&#xff0c;它首先检查这个类是否已经被加载、链接和初始化。如果没有&#xff0c;JVM会通过类加载器&#xff08;ClassLoader&#xff…...

详解TCP的三次握手

TCP&#xff08;三次握手&#xff09;是指在建立一个可靠的传输控制协议 (TCP) 连接时&#xff0c;客户端和服务器之间的三步交互过程。这个过程的主要目的是确保连接是可靠的、双方的发送与接收能力是正常的&#xff0c;并且可以开始数据传输。下面是对每个步骤的详细解释&…...

Java面试篇基础部分-Java创建线程详解

导语   多线程的方式能够在操作系统的多核配置上更好的利用服务器的多个CPU的资源,这样的操作可以使得程序运行起来更加高效。Java中多线程机制提供了在一个进程内并发去执行多个线程,并且每个线程都并行的去执行属于线程处理的自己的任务,这样可以提高程序的执行效率,让…...

Ubuntu 20.04/22.04无法连接网络(网络图标丢失、找不到网卡)的解决方案

问题复述&#xff1a; Ubuntu 20.04无法连接到网络&#xff0c;网络连接图标丢失&#xff0c;网络设置中无网络设置选项。 解决方案 对于Ubuntu 20.04而言&#xff1a;逐条执行 sudo service network-manager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo…...

《MDTv2- Masked Diffusion Transformer is a Strong Image Synthesizer》

论文摘要 论文提出了一种名为**Masked Diffusion Transformer (MDT)**的新模型&#xff0c;旨在增强扩散概率模型&#xff08;DPMs&#xff09;在图像合成中的上下文推理能力。通过引入掩码潜在建模方案&#xff0c;MDT能够显著提升DPMs在图像中对象部分之间关系的学习能力&am…...

算法 - 二分查找

算法 - 二分查找 今天继续八股文学习&#xff0c;看一下比较常规的几个算法 二分查找是一个基于分治策略的搜索方法&#xff0c;简单的理解就是每次都缩小一轮搜索范围&#xff0c;从中间search一次&#xff0c;直到搜索到结果或者为空为止。 基本思路&#xff08;设一个有序的…...

Python知识点:如何使用Python进行图像批处理

在Python中进行图像批处理可以使用多种库&#xff0c;如 Pillow、OpenCV 和 imageio。这些库可以用来执行各种图像处理任务&#xff0c;如调整大小、裁剪、旋转、滤镜应用等。以下是使用这些库进行图像批处理的示例。 使用 Pillow 进行图像批处理 Pillow 是一个功能强大的图像…...

数据结构实验1

实验题1&#xff1a;求1到n的连续整数和 题目描述 编写一个程序,对于给定的正整数n,求12…十n,采用逐个累加与(n1)/2(高斯法)两种解法。对于相同的n,给出这两种解法的求和结果和求解时间,并用相关数据进行测试。 运行代码 //实验题1&#xff1a;求1到n的连续整数和 #includ…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...