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

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


http://www.kler.cn/a/308495.html

相关文章:

  • 【Java SE】接口类型
  • Unity3D学习FPS游戏(11)敌人AI巡逻(NavMesh)
  • Java复习42(PTA)
  • Apache ECharts
  • Android 进入浏览器下载应用,下载的是bin文件无法安装,应为apk文件
  • PHP爬虫快速获取京东商品详情(代码示例)
  • 校园管理系统创新:Spring Boot框架应用案例
  • 文心智能体 城市印象之漫行北京 开发分享
  • 大舍传媒-日本媒体发稿推荐今日东京tokyotoday
  • grep 命令:文本搜索
  • 无畏契约 (Valorant)YOLO 模型数据集
  • 在Unity UI中实现UILineRenderer组件绘制线条
  • 音视频直播应用场景探讨之RTMP推流还是GB28181接入?
  • 仓储管理系统的设计与实现SSM框架
  • python数据分析 pandas库-数据的读取和保存
  • 【Linux 从基础到进阶】KVM虚拟化配置与管理
  • unity3d入门教程四
  • SprinBoot+Vue宠物寄养系统的设计与实现
  • PCL 曲线点云提取
  • Qt常用控件——QTextEdit
  • FPGA编程指南: CSU DMA传输
  • el-table表格的展开行,初始化的时候展开哪一行+设置点击行可展开功能
  • Python爬虫之bs4模块用法
  • 如何用python做一个计算器
  • 基于AlexNet实现猫狗大战
  • 轻松上手Cursor,体验丝滑编程