【iOS】push和present的区别

【iOS】push和present的区别

文章目录

  • 【iOS】push和present的区别
    • 前言
    • push
      • pop
    • present
      • dismiss
      • 简单小demo来展示dismiss和present
      • dismiss多级
    • push和present的区别
        • 区别
        • 相同点

前言

在iOS开发中,我们经常性的会用到界面的一个切换的问题,这里我们需要理清有关视图控制器的push和present的相关方法的区别,以及两种切换方式所对应的视图控制器的形式。

push

这里先给出一个push的简单代码。

ViewController4* vc2 = [[ViewController4 alloc] init];
[self.navigationController pushViewController:vc2 animated:YES];

我们通过这两个语句就可以实现一个push出一个视图控制器的效果,这里讲一下push的原理。

pushViewController:animated: 方法用于将新的视图控制器推入导航栈。这意味着新控制器将显示在当前控制器的上方,同时当前控制器仍然在堆栈中。

pop

push方法对应pop,pop有主要分成两个类别:

  • 第一个类别就是返回到上一层
 [self.navigationController popViewControllerAnimated:YES];
  • 第二个类别就是返回到某一层
[self.navigationController popToRootViewControllerAnimated:YES];//这个是返回到根视图
[self.navigationController popToViewController:viewController animated:YES];//返回指定的某一层视图控制器

这里我们返回某一层的视图控制器可以通过这种方式来返回self.navigationController.viewControllers[i]这里的i是你需要的viewController的层级也可以采用for循环通过判断我们的一个view是否符合isKindeOfClass这个方法来找到对应的UIView,来实现返回某一层的ViewController。

这个给出一个样例:


#import "ViewController3.h"
#import "ViewController4.h"
@interface ViewController3 ()@end@implementation ViewController3- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.greenColor;UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(200, 300, 100, 100);[button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];[button setTitle:@"切换" forState:UIControlStateNormal];[button setTitleColor:UIColor.blueColor forState:UIControlStateNormal];[self.view addSubview:button];// Do any additional setup after loading the view.
}
-(void)press {ViewController4* vc2 = [[ViewController4 alloc] init];[self.navigationController pushViewController:vc2 animated:YES];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
}
/*
#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
#import "ViewController1.h"
#import "ViewController2.h"
@interface ViewController1 ()@end@implementation ViewController1- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.whiteColor;UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(200, 300, 100, 100);[button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];[button setTitle:@"切换" forState:UIControlStateNormal];[button setTitleColor:UIColor.blueColor forState:UIControlStateNormal];[self.view addSubview:button];// Do any additional setup after loading the view.
}
-(void)press {ViewController2* vc2 = [[ViewController2 alloc] init];[self.navigationController pushViewController:vc2 animated:YES];
}
/*
#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#import "ViewController2.h"
#import "ViewController3.h"
@interface ViewController2 ()@end@implementation ViewController2- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.redColor;UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(200, 300, 100, 100);[button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];[button setTitle:@"切换" forState:UIControlStateNormal];[button setTitleColor:UIColor.blueColor forState:UIControlStateNormal];[self.view addSubview:button];// Do any additional setup after loading the view.
}
-(void)press {ViewController3* vc2 = [[ViewController3 alloc] init];[self.navigationController pushViewController:vc2 animated:YES];
}/*
#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

在这里插入图片描述

这里我是将设计第三层视图控制器如果点击就会返回第一层视图控制器。

present

下面先给出有关于present的简单代码:

ViewController3* vc2 = [[ViewController3 alloc] init];
[self presentViewController:vc2 animated:YES completion:nil];

dismiss

present方法对应dismiss

[self dismissViewControllerAnimated:YES completion:nil];

在我们的认知中的dismiss应该是一层一层逐级返回的,正如下面这个小demo一样。

简单小demo来展示dismiss和present


#import "ViewController1.h"
#import "ViewController2.h"
@interface ViewController1 ()@end@implementation ViewController1- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.whiteColor;UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(200, 300, 100, 100);[button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];[button setTitle:@"切换" forState:UIControlStateNormal];[button setTitleColor:UIColor.blueColor forState:UIControlStateNormal];[self.view addSubview:button];// Do any additional setup after loading the view.
}
-(void)press {ViewController2* vc2 = [[ViewController2 alloc] init];[self presentViewController:vc2 animated:YES completion:nil];
}
/*
#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#import "ViewController2.h"
#import "ViewController3.h"
@interface ViewController2 ()@end@implementation ViewController2- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = UIColor.redColor;UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];button.frame = CGRectMake(200, 300, 100, 100);[button addTarget:self action:@selector(press) forControlEvents:UIControlEventTouchUpInside];[button setTitle:@"切换" forState:UIControlStateNormal];[button setTitleColor:UIColor.blueColor forState:UIControlStateNormal];[self.view addSubview:button];// Do any additional setup after loading the view.
}
-(void)press {ViewController3* vc2 = [[ViewController3 alloc] init];[self presentViewController:vc2 animated:YES completion:nil];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self dismissViewControllerAnimated:YES completion:nil];
}
/*
#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

这里代码部分只展示两个视图控制器,因为四个视图控制器大致相同。

在这里插入图片描述

dismiss多级

但是present还有两个方法可以让我们实现一个跨级返回的效果。presentingViewControllerpresentedViewController这两个方法分别是什么呢?这里简单解释一下返回两个的对应视图控制器。

当从1中弹出2后:

  1. self.presentingViewController 在1中,就是nil;在2中,就是1
  2. self.presentedViewController在1中,就是2;在2中,就是nil

这里先给出一个通过dismisspresentingViewController这两个方法来实现多级返回的例子。

我们在原先的第四个视图控制器中设置多级返回的函数

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {//如果触碰屏幕就实现一个层级返回UIViewController* vc = [self presentingViewController];//设置一个vc来寻找他的viewcontrollerwhile (vc.presentingViewController) {//如果他的前一个视图控制器不是nil就继续寻找,说白了也就是寻找第一个视图控制器vc =  [vc presentingViewController];//不断向前寻找对应的present过的视图控制器。}[vc dismissViewControllerAnimated:YES completion:nil];
}

在这里插入图片描述

可以看到这里最后我们明明处于第一层视图控制器,却可以实现返回第一个视图控制器的效果,这里与我之前对于dismiss的理解有所不同,我一直认为是在后一层的视图控制器可以实现一个返回前一层的效果,但是实际上并非如此,这里我重新学习了一下dismiss这个函数的作用,附一段大佬的博客:你真的了解iOS中控制器的present和dismiss吗?

我们对于dismiss的调用一贯以来都是一个在2视图控制器这个位置调用,但是实际上这个方式是错误的,我们应该返回到他的上一层视图控制器也就是我们原先的1视图控制器:

实际上,dismiss方法系统会自动优化,当B视图控制器调用dismiss时,它并没有打开任何界面,就将dismissViewController方法会自动交给B的presentingViewController执行,也就是A来执行。

同时dismiss的真正意义在苹果官方文档里面是这样写的

如果你连续呈现多个视图控制器,从而构建一个呈现的视图控制器堆栈,那么在堆栈中较低的视图控制器上调用此方法将消除其直接的子视图控制器和堆栈上该子视图上方的所有视图控制器。发生这种情况时,只有最顶层的视图会以动画方式关闭;任何中间视图控制器都只是从堆栈中删除。最顶层的视图使用其模态过渡样式关闭,该样式可能与堆栈中较低的其他视图控制器使用的样式不同。苹果官方文档

所以这里如果我们按照上述的方法的正确的方式就是用第一个视图控制器调用dismiss方法,只有最上层的视图控制器会以动画方式关闭,其他仅仅是从代码层面上进行一个删除,然后就可以实现我们的这里的一个返回根视图控制器。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {UIViewController* vc = [self presentingViewController];vc =  [vc presentingViewController];[vc dismissViewControllerAnimated:YES completion:nil];
}

我们可以选择连续返回两层,只要修改这个函数成下面就可以实现这样的效果。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {UIViewController* vc = [self presentingViewController];vc =  [vc presentingViewController];[vc dismissViewControllerAnimated:YES completion:nil];
}

在这里插入图片描述

我们也可以通过判断视图控制器的类型来返回我们指定的视图控制器

这里我们的目标是返回推出的第二个视图控制器,其实内容差不多,只不过判断我们要返回那一个视图控制器,用判断类的方法来判断我们要返回的类。

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {UIViewController* vc = [self presentingViewController];while (![vc isKindOfClass:[ViewController2 class]]) {vc = [vc presentingViewController];}[vc dismissViewControllerAnimated:YES completion:nil];
}

push和present的区别

区别
  • push:
    • push 方法是通过 UINavigationController 进行导航,新的视图控制器会被压入导航栈中,可以跨级返回,push是由UINavigationController管理的视图控制器堆栈,在window下同时只能显示一个ViewController。 push一般用于同一业务不同界面间的切换。
  • present:
    • present 方法是通过模态展示的方式推出新的视图控制器,present是由UIViewController管理的视图控制器堆栈,在window下可以以叠加的方式展示,当顶层的view透明时可以看到底层的view,但只有顶层的view可用户交互,而且只能逐级返回(一般情况)。present一般用于不同业务界面的切换。
相同点
  • 两者都是用于切换界面的,只不过适用的业务逻辑不一样。

笔者这里简单学习了一下有关与push和present的区别,以及present的一些相关内容来实现一个多级跳转的功能,其实有关于视图控制器的内容很多,笔者简单总结了一部分。

参考博客:
苹果官方文档
你真的了解iOS中控制器的present和dismiss吗?

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

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

相关文章

网络(四)——HTTP协议

文章目录 认识urlurlencode和urldecodeHTTP协议格式HTTP的方法HTTP的状态码HTTP常见Header 虽然应用层的协议是由人为规定的&#xff0c;但是已经有大佬们定义了一些现成的&#xff0c;又非常好用的应用层协议&#xff0c;供我们直接参考使用. HTTP(超文本传输协议)就是其中之一…

适合骑行的开放式耳机哪个品牌好?四款开放式蓝牙耳机推荐

骑行时是否有必要佩戴耳机是一个需要权衡安全与便利的问题。因为虽然耳机能提供音乐、导航等功能&#xff0c;但也可能分散注意力&#xff0c;影响骑行安全。而且这也是需要看个人需求决定的&#xff0c;骑行戴耳机的需求是什么&#xff0c;我想大部分人应该就是为了接听电话&a…

[数据集][目标检测]无人机识别检测数据集VOC+YOLO格式6986张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;6986 标注数量(xml文件个数)&#xff1a;6986 标注数量(txt文件个数)&#xff1a;6986 标注…

MySQL —— 视图

概念 视图是一张虚拟的表&#xff0c;它是基于一个或多个基本表或其他视图的查询结果集。 视图本身不存储数据&#xff0c;而是通过执行查询来动态生成数据&#xff0c;用户可以像操作普通表一样使用视图来进行查询更新与管理等操作。 视图本身也不占用物理存储空间&#xf…

Redis基础数据结构之 Sorted Set 有序集合 源码解读

目录标题 Sorted Set 是什么?Sorted Set 数据结构跳表&#xff08;skiplist&#xff09;跳表节点的结构定义跳表的定义跳表节点查询层数设置 Sorted Set 基本操作 Sorted Set 是什么? 有序集合&#xff08;Sorted Set&#xff09;是 Redis 中一种重要的数据类型&#xff0c;…

SQL Server数据库简单的事务日志备份恢复

模拟数据库备份恢复过程 1.基础操作 1.创建TestDB数据库&#xff0c;并添加数据 USE [master] GO CREATE DATABASE TestDB CONTAINMENT NONE ON PRIMARY ( NAME NTestDB, FILENAME ND:\TestDB.mdf , SIZE 8192KB , MAXSIZE UNLIMITED, FILEGROWTH 65536KB ) LOG ON ( …

【ArcGIS Pro实操第七期】栅格数据合并、裁剪及统计:以全球不透水面积为例

【ArcGIS Pro实操第七期】批量裁剪&#xff1a;以全球不透水面积为例 准备&#xff1a;数据下载ArcGIS Pro批量裁剪数据集1 数据拼接2 数据裁剪3 数据统计&#xff1a;各栅格取值3.1 栅格计算器-精确提取-栅格数据特定值3.2 数据统计 4 不透水面积变化分析 参考 准备&#xff1…

DAY13信息打点-Web 应用源码泄漏开源闭源指纹识别GITSVNDS备份

#知识点 0、Web架构资产-平台指纹识别 1、开源-CMS指纹识别源码获取方式 2、闭源-习惯&配置&特性等获取方式 3、闭源-托管资产平台资源搜索监控 演示案例&#xff1a; ➢后端-开源-指纹识别-源码下载 ➢后端-闭源-配置不当-源码泄漏 ➢后端-方向-资源码云-源码泄漏 …

[C++进阶]AVL树

前面我们说了二叉搜索树在极端条件下时间复杂度为O(n),本篇我们将介绍一种对二叉搜索树进行改进的树——AVL树 一、AVL 树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找效率低下。因此&#xff0c;两位…

人工智能和大模型的简介

文章目录 前言一、大模型简介二、大模型主要功能1、自然语言理解和生成2、文本总结和翻译3、文本分类和信息检索4、多模态处理三、大模型的技术特性1、深度学习架构2、大规模预训练3、自适应能力前言 随着技术的进步,人工智能(Artificial Intelligence, AI)和机器学习(Mac…

Pytorch详解-Pytorch核心模块

Pytorch核心模块 一、Pytorch模块结构_pycache__Cincludelibautogradnnoptimutils 二、Lib\site-packages\torchvisiondatasetsmodelsopstransforms 三、核心数据结构——Tensor&#xff08;张量&#xff09;在深度学习中&#xff0c;时间序列数据为什么是三维张量&#xff1f;…

算法leecode笔记

具体代码&#xff1a; class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int, int> hashtable;for (int i 0; i < nums.size(); i) {auto it hashtable.find(target - nums[i]);if (it ! hashtable.end…

Git之如何删除Untracked文件(六十八)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

【计算机网络】UDP 协议详解及其网络编程应用

文章目录 一、引言二、UDP1、UDP的协议格式2、UDP 报文的解包和分用3、UDP面向数据报的特点 三、UDP输入输出四、UDP网络编程 一、引言 UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是一种网络通信协议&#xff0c;它属于传输层的协议。是一…

HTTP中的Cookie与Session

一、背景 HTTP协议是无状态无连接的。 无状态&#xff1a;服务器不会保存客户端历史请求记录&#xff0c;每一次请求都是全新的。 无连接&#xff1a;服务器应答后关闭连接&#xff0c;每次请求都是独立的。 无状态就导致服务器不认识每一个请求的客户端是否登陆过。 这时…

【贪心算法】贪心算法

贪心算法简介 1.什么是贪心算法2.贪心算法的特点3.学习贪心的方向 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.什么是贪心算法 与其说是…

Spring为什么要用三级缓存解决循环依赖?

Spring为什么要用三级缓存解决循环依赖&#xff1f; 1. Spring是如何创建一个bean对象2. Spring三级缓存2.1 一级缓存&#xff1a;单例池&#xff0c;经历过完整bean生命&#xff0c;单例Bean对象2.2 二级缓存&#xff1a;提前暴露的Bean2.3 三级缓存&#xff1a;打破循环 3. S…

计算机网络通关学习(一)

简介 之前我通过王道的考研课进行了计算机网络的学习&#xff0c;但是在秋招准备过程中发现之前的笔记很多不足&#xff0c;学习的知识不够深入和巩固&#xff0c;所以再重新对《图解HTTP》&《图解TCP/IP》进行深度学习后&#xff0c;总结出了此篇博客&#xff0c;由于内容…

08_Python数据类型_字典

Python的基础数据类型 数值类型&#xff1a;整数、浮点数、复数、布尔字符串容器类型&#xff1a;列表、元祖、字典、集合 字典 字典&#xff08;Dictionary&#xff09;是一种可变容器模型&#xff0c;它可以存储任意类型对象&#xff0c;其中每个对象都存储为一个键值对。…

存储数据的树形结构

目录 1、二叉查找树 2、平衡二叉树AVL Tree 3 、平衡多叉树B-Tree 4、BTree树 5 、红黑树 红黑树的应用 6.平衡树的旋转 mysql 索引数据结构&#xff1a; Btree 索引是B树在数据库中的一种实现&#xff0c;最为常见的。B树 中的B代表平衡&#xff0c;而不是二叉 1、二…