【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的生命周期

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/875236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL:bin log

redo log 它是物理日志,记录内容是“在某个数据页上做了什么修改”,属于 InnoDB 存储引擎。 而 binlog 是逻辑日志,记录内容是语句的原始逻辑,类似于“给 ID2 这一行的 c 字段加 1”,属于MySQL Server 层。 不管用什…

学习平台|基于java的移动学习平台系统小程序(源码+数据库+文档)

学习平台|学习平台系统|在线学习平台系统小程序 目录 基于java的移动学习平台系统小程序 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码…

C++奇迹之旅:快速上手Priority_queue的使用与模拟实现

文章目录 📝priority_queue的介绍和使用🌠 priority_queue的介绍🌉priority_queue的使用 🌠仿函数的使用🌠C语言有趣的模仿push_back🌠priority_queue的模拟实现🚩总结 📝priority_q…

java重点学习-集合(List)

七 集合(List) 7.1 复杂度分析 7.2 数组 1.数组(Array)是一种用连续的内存空间存储相同数据类型 数据的线性数据结构。 2.数组下标为什么从0开始 寻址公式是:baseAddressi*dataTypeSize,计算下标的内存地址效率较高 3.查找的时间复杂度 随机(…

HarmonyOS Next系列之实现一个左右露出中间大两边小带缩放动画的轮播图(十二)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…

一种多策略改进小龙虾智能优化算法MSCOA 改进策略:种群混沌映射初始化+透镜成像反向学习+黄金正弦变异策略

一种多策略改进小龙虾智能优化算法MSCOA 改进策略:种群初始化精英反向透镜成像反向学习黄金正弦变异策略 文章目录 一、小龙虾COA基本原理二、改进策略2.1种群初始化 映射2.2 透镜成像反向学习2.3 黄金正弦变异策略 三、实验结果四、核心代码五、代码获取六、总结 一…

小型企业如何利用人工智能的生产力

尽管生产力低下是一个长期存在的问题,但最近严峻的经济逆风加剧了这一问题,企业清算数量同比增长了 19%。 Xero 的报告《小企业生产力:趋势、影响和战略》反映了这些宏观经济变化,显示 2023 年新西兰小企业生产力与 …

SiC,GaN驱动优选驱动方案SiLM5350系列SiLM5350MDDCM-DG 带米勒钳位Clamp保护功能 单通道隔离栅极驱动器

SiLM5350MDDCM-DG是一款适用于IGBT、MOSFET的单通道 隔离门极驱动器,具有10A拉电流和10A灌电流驱动能 力。提供内部钳位功能,可单独控制 上升时间和下降时间。 在 SOP8 封 装 中 具 有 3000VRMS 隔 离 耐 压 ( 符 合 UL1577)。 与…

抖音微信超火国庆节国旗头像生成源码

源码介绍: 抖音微信超火国庆节国旗头像生成源码,静态页前端生成速度超快!源码直接上传到服务器即可使用。 1、打开地址后点击上传->选一张你喜欢的头像->然后点右边箭头符合选款式->最后点保存头像->按照提示 2、保存到手机即…

c/c++面试100道

1.一道笔试题解析_哔哩哔哩_bilibili P20:#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER) 1、 offsetof 宏是 C 语言中用于计算结构体成员相对于结构体起始地址的偏移量的宏定义。这个宏的定义如下: #define offsetof(TYPE, …

macOS上谷歌浏览器的十大隐藏功能

谷歌浏览器(Google Chrome)在macOS上拥有一系列强大而隐蔽的特性,这些功能能显著提高您的浏览体验。从多设备同步到提升安全性和效率,这些被低估的功能等待着被发掘。我们将逐步探索这些功能,帮助您最大化利用谷歌浏览…

09-排序1 排序(C)

这一节,测试各类排序算法的运行速度(没有基数排序(桶) 其实在实际学习中,还是有意义的 给定 n 个(长整型范围内的)整数,要求输出从小到大排序后的结果。 本题旨在测试各种不同的排序…

【代码随想录训练营第42期 Day57打卡 - 图论Part7 - Prim算法

一、Prim算法 Prim算法是一种贪心算法,用于求解加权无向图的最小生成树问题。其中,最小生成树是指一个边的子集,它连接图中的所有顶点,且边的总权重最小,并且没有形成环。 对于Prim算法的简单了解,这里推…

基于小程序的教学辅助微信小程序设计+ssm(lw+演示+源码+运行)

教学辅助微信小程序 摘 要 随着移动应用技术的发展,越来越多的学生借助于移动手机、电脑完成生活中的事务,许多的传统行业也更加重视与互联网的结合,由于学生学习的压力越来越大,教学辅助是一个非常不错的教育平台,对…

9.12-kubeadm方式安装k8s+基础命令的使用

一、安装环境 编号主机名称ip地址1k8s-master192.168.2.662k8s-node01192.168.2.773k8s-node02192.168.2.88 二、前期准备 1.设置免密登录 [rootk8s-master ~]# ssh-keygen[rootk8s-master ~]# ssh-copy-id root192.168.2.77[rootk8s-master ~]# ssh-copy-id root192.168.2.…

指令——计算机的语言(part 2)

目录 1.1 翻译并执行程序 1.1.1 编译器 1.1.2 汇编器 1.1.3 链接器 1.1.4 加载器 1.1.5 动态链接库 接上一篇文章: 指令——计算机的语言(part 1) 1.1 翻译并执行程序 程序翻译层次图如下: 首先高级语言比如说C,会被编译器编译成汇编语言,然后汇…

Python面试宝典第48题:找丑数

题目 我们把只包含质因子2、3和5的数称作丑数(Ugly Number)。比如:6、8都是丑数,但14不是,因为它包含质因子7。习惯上,我们把1当做是第一个丑数。求按从小到大的顺序的第n个丑数。 示例 1: 输入…

另类动态规划

前言&#xff1a;一开始我根本想不到这个题目是一个动态规划的题目&#xff0c;而且我一开始的初始状态还写错了 我还忘记了写算法题的基本步骤&#xff0c;先看数据范围&#xff0c;再考虑能不能用动态规划写 题目地址 #include <bits/stdc.h> using namespace std; #de…

3C电子胶黏剂在手机制造方面有哪些关键的应用

3C电子胶黏剂在手机制造方面有哪些关键的应用 3C电子胶黏剂在手机制造中扮演着至关重要的角色&#xff0c;其应用广泛且细致&#xff0c;覆盖了手机内部组件的多个层面&#xff0c;确保了设备的可靠性和性能。以下是电子胶在手机制造中的关键应用&#xff1a; 手机主板用胶&…

浏览器百科:网页存储篇-IndexedDB介绍(十)

1.引言 在现代网页开发中&#xff0c;数据存储需求日益增多和复杂&#xff0c;传统的客户端存储技术如localStorage和sessionStorage已难以满足大型数据的存储和管理需求。为了解决这一问题&#xff0c;HTML5 引入了 IndexedDB&#xff0c;在本篇《浏览器百科&#xff1a;网页…