present/push的恩怨情仇
present/push的恩怨情仇
- push/pop
- 简介
- VC栈存储
- container view controller
- 优势
- dealloc
- navigationController
- 无navigationController的界面push
- 添加navigationController使其可以push
- 缺点
- self.navigationController的dismiss
- 1. 前面有从`present`到的界面
- 一个神奇的事情
- 2. 前面没有`present`到的界面
- present/dismiss
- 简介
- presentingViewController和presentedViewController
- 实验
- 总结
- 返回根视图---1
- dismiss
- 利用dismiss
- 但是
- 返回根视图---2
- 切换根视图的小问题
push/pop
简介
pushViewController 导航控制器入栈的方式切换页面
popViewController
导航控制器出栈的方式返回上一页面
VC栈存储
container view controller
container view controller 指的是VC的容器类,通过container view controller,我们可以很方便的管理子VC,实现VC之间的跳转等,iOS中container view controller包括 UINavigationController, UISplitViewController, 以及 UIPageViewController.
push/pop是将旧视图存储在了VC栈中,因此我们可以这样操作:
假如
从A—(push)—>B—(push)—>C—(push)—>D—(popToRootViewController)—>A
如果在D视图进行操作:
NSLog(@"%@",self.navigationController.viewControllers);
则会打印:
2019-09-28 19:42:50.576198+0800 1111[995:32530] ("<AViewController: 0x7fdc41d00480>","<BViewController: 0x7fdc3ec0a010>","<CViewController: 0x7fdc3ef1b1e0>","<DViewController: 0x7fdc3ef1b530>"
)
这就是push的VC栈的内容。
因此,我们可以进行这样的pop跳转:
[self.navigationController popToViewController:self.navigationController.viewControllers[0] animated:YES];
这是因为我们可以看到,viewControllers
是NSArray
类型的,所以可以通过下标跳转到指定界面。
优势
VC栈存储的优势在于:
可以直接跳转到根视图:
- 通过
popToRootViewController
方法,把栈清空,直接回到根视图。
- 通过
可以跳转到指定界面:
- 通过
popToViewController:
方法 和NSArray
类型的viewControllers
,可以跳转到指定的视图。
- 通过
dealloc
那么,在我们通过popToRootViewController
方法回到根视图的时候,A视图后面的B、C、D视图会怎样呢?
答案是:按数组顺序依次销毁。
可以通过在B、C、D视图添加:
- (void)dealloc {NSLog(@"当前视图名称 dealloc");
}
可以发现,最后会这样打印:
2019-09-28 20:00:39.291619+0800 1111[1108:40814] AViewController viewWillAppear
2019-09-28 20:00:39.296359+0800 1111[1108:40814] BViewController dealloc
2019-09-28 20:00:39.296798+0800 1111[1108:40814] CViewController dealloc
2019-09-28 20:00:39.802419+0800 1111[1108:40814] DViewController dealloc
会先出现A视图,然后按数组顺序依次dealloc。
也就是说,它是按栈存储的,但是并不符合后进先出的原理。(???)
可能是把栈里的视图先取出,放到里另一个栈sNew里,当top指的是根视图时,先把根视图显示,再把栈sNew里的视图依次移除
navigationController
讨论push/pop
,就不得不讨论navigationController
。
无navigationController的界面push
当我们从一个有navigationController
的A界面用present
跳转到B界面后,B界面将没有navigationController
,若还在B界面用push
方法,即如下:
CViewController *cViewController = [[CViewController alloc]init];NSLog(@"跳转到C界面");[self.navigationController pushViewController:cViewController animated:YES];
则界面不会跳转,会一直停留在B界面,并且会触发C界面的dealloc
方法(不会触发loadView
方法):
2019-09-28 20:29:08.648083+0800 1111[1270:53904] 跳转到C界面
2019-09-28 20:29:08.648264+0800 1111[1270:53904] CViewController dealloc
添加navigationController使其可以push
假如我们想要达到这样的效果:
A—(present)—>B—(present)—>C—(push)—>D
B界面到C界面用present
方法到原因前面已经讲过里,那么我们如何达到由present
到的可以使用push
方法呢?
这时就可以给要present到界面加个navigationController
了:
CViewController *cViewController = [[CViewController alloc]init];UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:cViewController];[self presentViewController:nav animated:YES completion:nil];
这时,在C界面,就可以使用push
方法到达D界面了。
缺点
但是,这样到操作有个缺点:会把VC栈更新,也就是说,我们找不会之前的根视图了,新的根视图会变成C,在D界面进行打印,结果如下:
2019-09-28 21:00:16.317749+0800 1111[1503:67795] ("<CViewController: 0x7fd9d9513bd0>","<DViewController: 0x7fd9d9510af0>"
)
self.navigationController的dismiss
看到这个是不是感觉很神奇?
不是只有self
才能调用dismiss方法,self.navigationController
也可以调用这个方法,那这个方法有什么效果呢?
(其实直接self调用得到的结果也一样)
1. 前面有从present
到的界面
若是前面有从present
到的界面,那么会回到第一个present
到的界面
例如:
A—(present)—>B—(present)—>C—(push)—>D
在D界面进行:
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
则会直接回到B界面,且C、D界面将会销毁:
2019-09-28 21:32:56.522269+0800 1111[1822:83303] CViewController dealloc
2019-09-28 21:32:56.522559+0800 1111[1822:83303] DViewController dealloc
一个神奇的事情
发现dismiss到B界面时,C、D界面的销毁顺序不定:
2019-09-28 21:56:16.228338+0800 1111[2062:94506] DViewController dealloc
2019-09-28 21:56:16.228534+0800 1111[2062:94506] CViewController dealloc
这…恕我能力有限,不知道为什么…
2. 前面没有present
到的界面
会停留在本界面
例如:
A—(push)—>B—(push)—>C—(push)—>D
在D界面进行:
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
则会停留在D界面,不发生跳转。
present/dismiss
简介
presentViewController
/ dismissViewController
模态切换的方式切换页面
(压入一个新视图和弹出顶层视图)
(要逐级跳转)
presentViewController
弹出,出现一个新视图
presentingViewController和presentedViewController
既然讲到present
,就不得不讲一下presentingViewController
和presentedViewController
了。
实验
例如:
A—(present)—>B
那么对于A来说:
2019-09-29 01:02:26.510791+0800 1111[4015:194177] AViewController presented--------<BViewController: 0x7f889e507e70>
2019-09-29 01:02:26.510873+0800 1111[4015:194177] AViewController presenting--------(null)
那么对于B来说:
2019-09-29 01:03:28.802197+0800 1111[4035:196590] BViewController presented--------(null)
2019-09-29 01:03:28.802321+0800 1111[4035:196590] BViewController presenting--------<AViewController: 0x7ff2c58062b0>
总结
presented
代表到是当前界面的子视图
presenting
代表到是当前界面的父视图
返回根视图—1
在知道push
可以利用栈存储的方法,轻松跳转回根视图后,不妨想想present
可不可以直接跳回根视图?又是怎么跳转的?
dismiss
要弄清楚如何跳转到根视图,我们可以先弄清楚dismiss
的原理。
- 在某一视图中dismiss ,它会找从当前视图 present 的视图,这时候会有2种可能:
- 当前视图没有
present
的视图,这时候,它就会返回到presenting
视图(父视图),触发父视图的dismiss
,把自己dealloc
掉 - 当前视图有
present
的视图,这时候,它会停留在当前视图,并把prsented
视图(子视图)全部dealloc
- 当前视图没有
例如:
A—(present)—>B—(present)—>C—(present)—>D
如果在A界面进行dismiss操作,则会跳回A界面,并把B、C、D界面dealloc
,结果如下:
2019-09-29 00:07:41.900487+0800 1111[3562:152312] DViewController dealloc
2019-09-29 00:07:41.900944+0800 1111[3562:152312] CViewController dealloc
2019-09-29 00:07:41.901692+0800 1111[3562:152312] AViewController viewWillAppear
2019-09-29 00:07:42.405926+0800 1111[3562:152312] BViewController dealloc
利用dismiss
这样,我们就可以利用dissmiss
这个原理,轻松的从D界面回到A界面。
也就是说,只要我们能在A界面调用到dismiss
方法,就可以返回A界面了。
那么,我们如何在D界面点击按钮到时候,触发A界面到dismiss
方法呢?
这时候,我们会想到传值,而在那么多多传值方法里,能最简单让多个界面响应的,当然是通知传值啦。
因此,我们在D界面写:
[[NSNotificationCenter defaultCenter]postNotificationName:@"back to A" object:nil];
在A界面的viewDidLoad里面写:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backA) name:@"back to A" object:nil];
并在A界面添加backA
方法:
-(void)backA {[self dismissViewControllerAnimated:YES completion:nil];
}
这样,就可以实现回到根视图的要求了。
但是
但是,这样的返回根视图,并不是直接到达的根视图,而是会经过中间的所有界面。
还是这个例子:
A—(present)—>B—(present)—>C—(present)—>D
如果在B、C、D界面重写viewWillAppear
和dealloc
方法:
- (void)dealloc {NSLog(@"当前视图名称 dealloc");
}- (void)viewWillAppear:(BOOL)animated {NSLog(@"当前视图名称 viewWillAppear");
}
进行A界面的dismiss操作,这时候,会发现打印情况如下:
2019-09-29 00:07:41.896396+0800 1111[3562:152312] CViewController viewWillAppear
2019-09-29 00:07:41.898284+0800 1111[3562:152312] BViewController viewWillAppear
2019-09-29 00:07:41.900487+0800 1111[3562:152312] DViewController dealloc
2019-09-29 00:07:41.900944+0800 1111[3562:152312] CViewController dealloc
2019-09-29 00:07:41.901692+0800 1111[3562:152312] AViewController viewWillAppear
2019-09-29 00:07:42.405926+0800 1111[3562:152312] BViewController dealloc
通过打印情况,我们可以发现,在回到A界面的过程中,其实是经过了B、C界面的。
返回根视图—2
在上面,利用了通知 加 dismiss
的方法达到了返回根视图的目的(其实也可以返回指定视图),其实还有一种方法。
新写一个继承于UIViewController
的Base_VC
,并且写上一个方法:
-(void)toRootViewController{UIViewController *viewController = self;while (viewController.presentingViewController) {//判断是否为最底层控制器if ([viewController isKindOfClass:[Base_VC class]]) {viewController = viewController.presentingViewController;}else{break;}}if (viewController) {[viewController dismissViewControllerAnimated:YES completion:nil];}
}
再以此Base_VC
继承,创建A、B、C、D界面,这样就会逐级判断,直到到达根视图,执行dismiss
操作。
详细操作可以看这篇博客(有源码):
多级presentViewController直接返回一级界面
切换根视图的小问题
切换根视图
还是这个例子:
A—(present)—>B—(present)—>C—(present)—>D
若是在C界面跳转到D界面的时候,并不是直接跳转,而是把D界面设为了根视图,那么A、B、C界面会怎样呢?
根据实验,我们得知,把D设为了根视图,但是A、B、C界面依旧存在,当D界面较小时,我们可以看到底下的A、B、C界面。
在A、B、C界面重写dealloc
方法:
- (void)dealloc {NSLog(@"当前视图名称 dealloc");
}
查看打印情况:
2019-09-29 13:01:50.277999+0800 1111[1759:50148] AViewController viewWillAppear
2019-09-29 13:01:52.786515+0800 1111[1759:50148] BViewController viewWillAppear
2019-09-29 13:01:53.575938+0800 1111[1759:50148] CViewController viewWillAppear
2019-09-29 13:01:54.376980+0800 1111[1759:50148] DViewController viewWillAppear
发现,A、B、C界面并没有执行dealloc
方法,即没有销毁视图,那么我们应该如何使其销毁呢?
我们会想到在A界面dismiss
的办法,这样的打印结果又是怎样的呢?
2019-09-29 13:07:51.106658+0800 1111[1825:53044] BViewController viewWillAppear
2019-09-29 13:07:51.107801+0800 1111[1825:53044] CViewController dealloc
2019-09-29 13:07:51.109261+0800 1111[1825:53044] AViewController viewWillAppear
2019-09-29 13:07:51.612881+0800 1111[1825:53044] BViewController dealloc
2019-09-29 13:07:51.613156+0800 1111[1825:53044] AViewController dealloc
可以看到,A、B、C界面都执行了dealloc
方法,打算但是我们看手机,会发现,虽然A界面销毁了,可是依旧在D界面的下面显示着。
???
这就很神奇了,通过百度查找(iOS连续dismiss几个ViewController的方法,以及切换根视图我遇到的问题 - 简书)
发现了一种方法:
在C界面跳转到D界面处写:
[[NSNotificationCenter defaultCenter]postNotificationName:@"back to A" object:nil];
在A界面的viewDidLoad
写:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backA) name:@"back to A" object:nil];
最后,在通知的方法里写:
-(void)backA {[self dismissViewControllerAnimated:YES completion:^{DViewController *dViewController = [[DViewController alloc]init];[UIApplication sharedApplication].delegate.window.rootViewController = dViewController;}];
}
最后手机屏幕上只剩下D界面,且打印结果如下:
2019-09-29 13:00:09.846634+0800 1111[1726:48963] BViewController viewWillAppear
2019-09-29 13:00:09.848979+0800 1111[1726:48963] CViewController dealloc
2019-09-29 13:00:09.849789+0800 1111[1726:48963] AViewController viewWillAppear
2019-09-29 13:00:10.354176+0800 1111[1726:48963] DViewController viewWillAppear
2019-09-29 13:00:10.355783+0800 1111[1726:48963] BViewController dealloc
2019-09-29 13:00:10.357705+0800 1111[1726:48963] AViewController dealloc
也就是说,要在dismiss
执行后,再切换根视图,就可以成功的将之前的界面dealloc
掉,并且屏幕上只留新的根视图。
present/push的恩怨情仇相关推荐
- 漫画:前端发展史的江湖恩怨情仇
作者 | 前端布道师 来源 | 前端布道师(ID:honeyBadger8) 时间总是过得很快, 似乎快得让人忘记了昨天,前端WEB领域的发展更是如此,转眼间已是近30年,时光荏苒,初心不变,在一代又 ...
- 宏观与量子的恩怨情仇
第四章:宏观与量子的恩怨情仇 我们知道哥本哈根诠释由波尔和海森堡于1927年在哥本哈根合作研究时共同提出的.此诠释建立在由德国数学家.物理学家Max Born所提出的"波函数的概率表达&qu ...
- [你必须知道的.NET]第一回:恩怨情仇:is和as
本文将介绍以下内 容: • 类型转换 • is/as操作符小议 1. 引言 类型安全是.NET设计之初重点考虑 的内容之一,对于程序设计者来说,完全把握系统数据的类型安全,经常是力不从心的问题.现在, ...
- [你必须知道的.NET] 第一回:恩怨情仇:is和as
发布日期:2007.4.7 作者:Anytao ©2007 Anytao.com 转贴请注明出处,留此信息. 本文将介绍以下内容: • 类型转换 • is/as操作符小议 1. 引言 类型安全是.NE ...
- 红帽 与 CentOS 之间的恩怨情仇
[CSDN 编者按]红帽正式宣布 CentOS 8 于 2021年底结束支持,后续将由 CentOS Stream 接班.一起来看看红帽与 CentOS 的"恩怨情仇"-- 参考链 ...
- Usdt到底靠谱吗?——记美国与大B网的恩怨情仇
Usdt到底靠谱吗?--记美国与大B网的恩怨情仇 在介绍之前,首先为小白科普几个Usdt的问题,方便大家阅读. Usdt是什么? Usdt是Tether公司的发行的一个基于区块链技术的代币,发行之时对 ...
- 钟汉良日记:网络也是江湖,有恩怨情仇有利益纠葛
2022年10月5日 周三 天气多云 这几天我写的日记,少了一个平台,猜一猜是哪个平台?其实,就是知乎这个问答平台,谈到乐买买,被关小黑屋了. 我的日记在知乎上更新了三十多篇了,获得的阅读量少的可怜, ...
- 乔布斯与比尔盖茨的传奇人生 两位天才的恩怨情仇
摘要:苹果公司联合创始人乔布斯的去世,让世人惋惜,这位天才的影响力远远超出PC行业,他改变了人们的生活方式,也影响着我们对生活的态度.作为美国两大影响世界的人物,苹果创始人乔布斯与比尔盖茨经常被人拿出 ...
- 细数研究生和导师的那些恩怨情仇
阅读本文大概需要 5 分钟. 作者:黄小斜 这篇文章其实我很早之前就想写了,没想到最近又出了一件类似的事情,事情就发生在我刚毕业不久的学校,事情始末想必大家都已经看过,震惊和惋惜之余,更多的是思考. ...
最新文章
- colab找不到模块 no name
- Iptables防火墙配置详解
- java扫描注解_使用Spring Java注释扫描
- 在python中等号前面与后面分别是什么意思-Python中冒号等于(:=)是什么意思?...
- bat窗口大小设置_Tomcat的JVM和连接数设置
- qt乱码Could not decode“xxx.cpp“ with “UTF-8“-encoding.Editing not possible问题处理
- [BUGKU][CTF][Reverse][2020] Reverse writeup 1-7 暂时肝不动了
- 钉钉功能介绍_平棉集团组织召开阿里钉钉办公系统基础功能培训会
- Zernike函数拟合曲面--MATLAB实现
- 【Java】Springboot项目中Transactional的使用方式
- 2019年,区块链不得不知的 9 件大事!
- linux fcntl函数,Linux C 学习之 - fcntl 函数
- 软件开发人员的简历项目经验怎么写?
- SpringBoot项目下载resources目录下模板文件
- OpenCV: 读取图片中某个点的像素值
- Manjaro 安装搜狗输入法
- 中国象棋马走日(要求打印每一种走法) — 递归
- element-ui input 身份证号码验证
- 推荐!十个好用的百度网盘搜索引擎
- 车羊问题c语言编程,再谈“羊车门”问题