iOS——ViewController的生命周期

news2024/11/15 16:32:05

ViewController

ViewController的生命周期是指在应用程序运行过程中,ViewController实例从创建到销毁的整个过程。在这个过程中,ViewController会经历一系列的生命周期方法,这些方法可以帮助开发者管理ViewController及其相关的视图和逻辑。

ViewController的生命周期可以分为以下几个阶段:

  1. 创建阶段:在应用程序启动时,系统会根据需要创建ViewController实例。在创建阶段,ViewController会调用一些生命周期方法。当你alloc并init了一个ViewController时,这个ViewController应该是还没有创建view的。ViewController的view是使用了lazyInit方式创建,就是说你调用的view属性的getter:[self view]。
  2. 视图加载阶段:在应用程序需要显示ViewController的视图时,系统会调用ViewController的loadView方法。在这个方法中,ViewController会创建并加载视图控制器的视图。在view属性的getter里会先判断view是否创建,如果没有创建,那么会调用loadView来创建view。loadView完成时会继续调用viewDidLoad。loadView和viewDidLoad的一个区别就是:loadView时还没有view。而viewDidLoad时view以及创建好了。
  3. 视图控制器显示阶段:在视图加载完成后,ViewController会进入视图控制器显示阶段。在这个阶段,ViewController会调用一些生命周期方法,例如viewDidLoad、viewWillAppear:和viewDidAppear:。当view被添加其他view中之前时,会调用viewWillAppear,而之后会调用viewDidAppear。当view从其他view中移出之前时,会调用viewWillDisAppear,而之后会调用viewDidDisappear。
  4. 视图控制器销毁阶段:在应用程序不再需要ViewController时,系统会销毁ViewController实例。在销毁阶段,ViewController会调用一些生命周期方法,例如viewWillDisappear:和viewDidDisappear:。

ViewController的生命周期是一个复杂的过程,开发者需要了解这个过程,才能正确地管理ViewController及其相关的视图和逻辑。

注意:
1、init里不要出现创建view的代码。良好的设计,在init里应该只有相关数据的初始化,而且这些数据都是比较关键的数据。init里不要调用self.view,否则会导致viewcontroller创建view。(因为view是lazyinit的)(文章下方细说)。
2、loadView中只初始化view,一般用于创建比较关键的view如tableViewController的tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super loadView前),最好也不要初始化一些非关键的view。如果你是从nib文件中创建的viewController在这里一定要首先调用super的loadView方法,但建议不要重载这个方法。
3、viewDidLoad 这时候view已经有了,最适合创建一些附加的view和控件了。有一点需要注意的是,viewDidLoad会调用多次(viewcontroller可能多次载入view,参见图2)。
4、viewWillAppear 这个一般在view被添加到superview之前,切换动画之前调用。在这里可以进行一些显示前的处理。比如键盘弹出,一些特殊的过程动画(比如状态条和navigationbar颜色)。
5、viewDidAppear 一般用于显示后,在切换动画后,如果有需要的操作,可以在这里加入相关代码。
6、viewDidUnload 这时候viewController的view已经是nil了。由于这一般发生在内存警告时,所以在这里你应该将那些不在显示的view释放了。比如你在viewcontroller的view上加了一个label,而且这个label是viewcontroller的属性,那么你要把这个属性设置成nil,以免占用不必要的内存,而这个label在viewDidLoad时会重新创建。

loadView和viewDidLoad的区别:
loadView时view还没有生成,viewDidLoad时,view已经生成了,loadView只会被调用一次,而viewDidLoad可能会被调用多次(View可能会被多次加载),当view被添加到其他view中之前,会调用viewWillAppear,之后会调用viewDidAppear。当view从其他view中移除之前,调用viewWillDisAppear,移除之后会调用viewDidDisappear。当view不再使用时,受到内存警告时,ViewController会将view释放并将其指向为nil。
在这里插入图片描述

  • init
    初始化ViewController本身。
  • loadView
    当View需要被展示而它却是nil时,ViewController会调用该方法。
    如果代码维护View的话需要重写此方法,使用xib维护View的话不用重写。
  • viewDidLoad
    执行完loadView后执行viewDidLoad,loadView还没有View,而viewDidLoad时View已经创建好了,一般的控件在此方法初始化。
  • viewWillAppear
    UIViewController对象的视图即将加入窗口时调用。
  • viewDidAppear
    UIViewController对象的视图已经加入到窗口时调用。
  • viewWillDisappear
    UIViewController对象的视图即将消失、被覆盖或是隐藏时调用。
  • viewDidDisappear
    UIViewController对象的视图已经消失、被覆盖或是隐藏时调用。
  • viewDidUnload
    一般发生在内存警告时。这时候viewController的view已经是nil了。由于这一般发生在内存警告时,所以在这里你应该将那些不在显示的view释放了。比如你在viewcontroller的view上加了一个label,而且这个label是viewcontroller的属性,那么你要把这个属性设置成nil,以免占用不必要的内存,而这个label在viewDidLoad时会重新创建。
  • dealloc
    释放其他资源或内存。
  • 注意
    不要在loadView中调用父类方法[super loadView],因为这会影响CPU性能。
    切换前后台不会调用viewWillAppear。

代码实现:
首先我们在ViewController中创建一个按钮,然后按钮的事件函数是跳转到另一个视图控制器。

#import "ViewController.h"
#import "QieHuanViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"切换视图" forState:UIControlStateNormal];
    button.frame = CGRectMake(100, 700, 100, 80);
    [self.view addSubview:button];
}

- (void) press {
    QieHuanViewController *qieHuanView = [[QieHuanViewController alloc] init];
    [self presentViewController:qieHuanView animated:YES completion:nil];
}

@end

然后在被跳转的视图控制器中使用ViewController生命周期相关的方法:

#import "QieHuanViewController.h"
#import "ViewController.h"

@interface QieHuanViewController ()

@end

@implementation QieHuanViewController

//加载View的时候调用
- (void)loadView {
    self.view = [[UIView alloc] init];
    NSLog(@"view正在加载");
}

//view加载完成后调用
- (void)viewDidLoad {
    self.view.backgroundColor = [UIColor orangeColor];
    UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(100, 300, 200, 200)];
    subView.backgroundColor = [UIColor blueColor];
    [self.view addSubview:subView];
    
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    [button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"切换视图" forState:UIControlStateNormal];
    button.frame = CGRectMake(100, 700, 100, 80);
    [self.view addSubview:button];
}

//view将要显示出来时调用
- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"view即将显示");
}

//view已经显示出来时调用
- (void)viewDidAppear:(BOOL)animated {
    NSLog(@"view已经显示");
}

//view将要消失的时候调用
- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"view将要消失");
}

//view已经消失的时候调用
- (void)viewDidDisappear:(BOOL)animated {
    NSLog(@"view已经消失");
}

- (void)press {
    [self dismissViewControllerAnimated:YES completion:nil];
}

@end

演示结果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

loadView 死循环,loadView 及使用loadView中初始化View注意的问题

在我写上方的代码时,一开始只是在重写loadView时写了NSLog的代码,于是发生了死循环,我查阅了一些资料找到了问题所在:
首先,我的loadView方法发生死循环的原因:

  1. ViewController中的loadView方法中没有做任何实例化self.view的操作。如没有执行[supper loadView]或者[[UIView alloc] init];
  2. 在viewDidLoad中调用了self.view。
  3. 没有XIB。

满足了以上三个条件,代码必定发生死循环。当self.view没有实例化的时候,在viewDidLoad中调用了self.view,因为self.view为nil,所以又回调到loadView来,但是loadView没有对其实例化,因此跑完loadView又跑到了viewDidLoad,这样就产生了死循环。

那么如何解决死循环呢?处理方式有三:

  1. 在loadView中,使用已实例化的View对Self.View进行赋值。注:是使用=号赋值,而不是使用[self.view addSubView]因为此时self.view 是空指针,执行ADD操作会崩溃的。
  2. 在loadView中添加一句[Supper LoadView],不过不建议这样写
  3. 把整个-(void)loadView 屏蔽掉。让父类自己来创建一个view。这个是最常见的,因为ViewController产生的时候默认代码中是把这段代码给注释了的。当然这里我们要说ViewController的生命周期不能屏蔽它,显然这个方法是不能用的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

20230919在WIN10下使用python3将PDF文档转为DOCX格式的WORD文档

20230919在WIN10下使用python3将PDF文档转为DOCX格式的WORD文档 2023/9/19 11:20 python pdf word https://blog.csdn.net/u013185349/article/details/130059657 Python实现PDF转Word文档 AcceptedLin 已于 2023-04-10 14:45:17 修改 1243 收藏 1 文章标签: pd…

软件系统的测试方法

软件系统测试是确保软件质量和功能的关键步骤,选择适当的测试方法取决于项目的性质、需求和资源可用性。通常,综合运用多种测试方法可以更全面地评估软件系统的质量和性能。下面列举了一些常见的软件系统测试方法,希望对大家有所帮助。北京木…

通过http发送post请求的三种Content-Type分析

通过okhttp向服务端发起post网络请求,可以通过Content-Type设置发送请求数据的格式。 常用到的三种: 1)application/x-www-form-urlencoded; charsetutf-8 2)application/json; charsetutf-8 3)multipart/form-dat…

数据融合的并行计算

1、 数据融合的算法 数据融合的算法当中,需要对每一个格点i进行逐个计算,公式如下 2、出现的问题 但是随着背景场的空间分辨率的提高,格点数急剧增加。如空间分辨率为0.01的话,那么15✖15的空间范围内就有1500✖1500个格点。那…

003 linux 自动化构建工具-make/makefile

前言 本文将会向您介绍make/makefile的原理与操作 引入 首先先向您介绍linux的编译器gcc的编译过程: 预处理 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。 预处理指令是以#号开头的代码行。 实例: gcc –E hello.c –o hello.i 选项“-E”,该选项的作…

iOS线上闪退问题解决方案

iOS线上闪退问题的收集工具是关键,它们可以帮助你及时发现和解决应用程序中的崩溃问题。以下是一些常用的iOS线上闪退问题收集工具及其使用方法,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合…

POJ 3977 Subset 折半枚举+二分搜素+双指针

一、题目大意 我们有N&#xff08;N<35&#xff09;个元素&#xff0c;从中选取一个子集&#xff0c;使得它的元素求和的绝对值最小&#xff0c;如果有多个可行解&#xff0c;选择元素最小的。 输出最优子集的元素总和绝对值&#xff0c;和最优子集元素的数量。 二、解题…

Google拟放弃博通自行研发AI芯片 | 百能云芯

谷歌计划自行研发人工智能&#xff08;AI&#xff09;芯片&#xff0c;考虑将博通&#xff08;Broadcom&#xff09;从其供应商名单中剔除&#xff0c;但谷歌强调双方的合作关系不会受到影响。 根据美国网络媒体《The Information》的报道&#xff0c;谷歌高层正在讨论可能在20…

窜货采买第三方怎么选择

窜货溯源服务听起来并不难&#xff0c;无非就是买货&#xff0c;但是否能买到货&#xff0c;同时在买到之后能否顺利完成溯源工作&#xff0c;也是非常有学问的&#xff0c;很多品牌会选择第三方服务商进行采买合作&#xff0c;这样可以规避品牌自己操作时的不合规性&#xff0…

Exploit-DB 使用小结

Exploit-DB &#xff08;网址&#xff1a;https://www.exploit-db.com&#xff09; 是一个漏洞库网站 &#xff0c;存储了大量的漏洞利用程序&#xff0c;可以帮助安全研究者和渗透测试工程师更好的进行安全测试工作&#xff0c;目前是世界上公开收集漏洞最全的数据库&#xff…

CNN(八):Inception V1算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 1 Inception V1 Inception v1论文 1.1 理论知识 GoogLeNet首次出现在2014年ILSVRC比赛中获得冠军。这次的版本通常称其为Inception V1。…

QtCreator报大量未知标识符错误的解决方法

目录 前言背景介绍问题1问题1解决方法问题2问题2 解决方法总结 前言 本文记录了在使用QtCreator开发时遇到的一个错误&#xff0c;导致编译时出现大量的“未知标识符”&#xff0c;经过一番努力最终解决了这个问题&#xff0c;特在此记录。 背景介绍 Qt项目在麒麟V10 系统下…

Linux中创建用户要自己设置密码

因为不知道Linux默认设置的密码&#xff0c;没办法接下来愉快的使用。如下&#xff1a; 而想要新建Linux用户密码&#xff0c;请您执行以下步骤: . 1.打开终端并以root身份登录; 2.输入命令“useradd username",其中username为您新建的用户名; 3.使用命令“passwd usernam…

《向量数据库指南》——向量搜索库Faiss 迁移到 Milvus 2.x

Faiss -> Milvus 2.x 1. Faiss 数据准备 前提条件是用户已经准备好了自己的 faiss 数据文件。(为了能快速体验,在项目源码的 testfiles 目录下放置了 faiss 测试数据方便用户体验: faiss_ivf_flat.index. 2. 编译打包 这部分同上,不再展开介绍。 3. 配置 migration.ymal…

【数据结构】顺序查找,折半查找,分块查找的知识点总结及相应的代码实现

目录 1、顺序查找 定义及步骤 代码实现 2、折半查找 定义及步骤 代码实现 折半查找判定树 3、分块查找 定义及步骤 1、顺序查找 定义及步骤 顺序查找的定义&#xff1a;从数据集合的起始位置开始&#xff0c;逐一比较每个数据元素&#xff0c;直到找到所要查找…

百度SEO优化不稳定的原因分析(提升网站排名的稳定性)

百度SEO优化不稳定介绍蘑菇号-www.mooogu.cn SEO不稳定是指网站在搜索引擎中的排名不稳定&#xff0c;随着时间的推移会发生变化。这种情况可能会出现在网站页面结构、内容质量、外链质量等方面存在缺陷或不合理之处。因此&#xff0c;优化SEO非常重要&#xff0c;可以提高网站…

4+机器学习+实验验证

今天给同学们分享一篇4机器学习实验验证的生信文章“Identification and Analysis of Neutrophil Extracellular Trap-Related Genes in Osteoarthritis by Bioinformatics and Experimental Verification”&#xff0c;这篇文章于2023年8月31日发表在 J Inflamm Res 期刊上&am…

两个数使用JavaScript比较大小;JavaScript知识点

一、两个数使用JavaScript比较大小代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><body><script type"text/javascript">var aprompt("请输入第一个数:"…

Web自动化测试 —— 如何进行Selenium页面数据及元素交互?啊哈

前言&#xff1a; Web自动化测试是一种常用的测试方式&#xff0c;通过在浏览器中模拟用户操作以及与页面元素的交互&#xff0c;可以有效地检验页面的功能性以及稳定性。Selenium是一款流行的Web自动化测试工具&#xff0c;在本篇文章中&#xff0c;我们将介绍如何使用Seleni…

青大数据结构【2022】

关键字&#xff1a; next数组、下三角矩阵、完全二叉树结点、静态分布动态分布、迪杰斯特拉最短路径、二叉排序树失败ASL、排序比较、二叉排序树中序遍历、链表删除最大值 一、单选 二、简答 三、应用 四、算法分析 五、算法设计