dismiss和remove_你真的了解iOS中控制器的present和dismiss吗?
一、了解present和dismiss
一个iOS开发,这个控制器的打开和关闭,应该是接触UIKit所接触的第一个关于UIViewController的API,然而,你真的了解它吗?
同样的,本文默认你已经了解UIViewController的present和dismiss方法,并多次运用。另外本文不再加OC语言的代码,毕竟都能读得懂swift。
二、谁来调用dismiss方法?
咱们从最基本的开始:一个控制器A,和一个控制器B。
A present B
让A打开B,在A中是这样写:
//A
let B = ViewController()
self.present(B, animated: true, completion: nil)
在B中需要关闭B的时候在B中这么写:
//B
self.dismiss(animated: true, completion: nil)
难道?这样写有问题?这....可能大多数开发者都是这么写,也没有出现过什么问题。但是...
YES,这样写在“理论”讲,是错误的。
别急,在实际上,这么写大多数情况是没有问题的,因为iOS系统帮我们做了很多。
三、presentingViewController和presentedViewController
想了解为什么说那么写在“理论上”是错误的,先从presentingViewController和presentedViewController说起。
为了不使本文枯燥,不引用大段描述和说明,只针对案例解释。当从A中弹出B后:
self.presentingViewController: 在A中,就是nil;在B中,就是A
self.presentedViewController:在A中,就是B;在B中,就是nil
那为什么说在B中调用dismiss在“理论上”是错的呢?因为有这么一个规则一定要记住!
谁污染,谁治理!
很熟悉对不对?MRC的法则,谁创建谁释放!所以A打开了B,当然是A来负责关闭!
正确写法是在A里调用self.dismiss(animated: true, completion: nil)。
等等,之前都是B里调用?没错,dismiss方法系统会自动优化,当B视图控制器调用dismiss时,它并没有打开任何界面,就将dismissViewController方法会自动交给B的presentingViewController执行,也就是A来执行。
如果现在A没有打开B的话,调用dismissViewController时它没有presentedViewController,转交给它的presentingViewController,但是它也没有presentingViewController,所以dismiss就不执行了。swift中可选型能很好的解释了:
self.presentingViewController?.dismiss(animated: true, completion: nil) //presentingViewController为nil,后面的不执行
扩展:关于实例为空的时候方法不执行,可百度“iOS消息转发”了解。
既然这样,说这个有毛用?
如果你从A打开了B,从B打开了C,现在怎么直接回到A?
你很可能会通过一些手段让B执行dismiss方法,但你会得到错误的结果,因为你这里如果交给B执行dismiss方法,和直接在C里面执行dismiss方法的效果是一样的,也就是说你到了B的界面并没有到A。
SO,dismiss方法必须让需要回到的这个控制器来执行。那么一个控制器的presentingViewController一定是打开它的那个控制器吗?继续往后看。
四、presentingViewController是打开它的那个控制器吗?
从上文,A打开了B,A是B的presentingViewController,那是不是所有的控制器的presentingViewController都是调用presnet方法打开自己的那个控制器呢?
NO!但是刚才A打开了B,不是说A是B的presentingViewController吗?当然,不是说一个控制器A弹出一个控制器B,A就一定是B的presentingViewController。
吃屁吧你
别着急,看几个图片娱乐一下:
第一种
这时箭头指向的控制器的presenting是谁?
第二种
这时箭头指向的控制器的presenting是谁?
第一个图片是navigationController,第二个是tabbarController。又跟你想的不一样了?看来你真的了解的太少,这时咱们得了解一下子控制器了。
四、子控制器childViewControllers
刚才在了解presentingViewController和presentedViewController的时候,如果你用代码试了一下,会发现parentViewController(OC中,swift叫parent),父控制器。有父就有子,每个控制器都有一个属性,叫做childViewControllers,存放它的子控制器。这里对childViewControllers的使用方法使用场景使用优势不做探讨。我们假设你了解并多次使用了子控制器来显示复杂界面的。
但是实际上只要你学习iOS的UIKit,你就肯定已经多次,甚至经常使用了这个东西。
我们知道,在一个有导航控制器的控制器P中加入了子控制器Q,然后添加了Q的view,这个Q就可以使用self.navigationController进行跳转,Q是利用的P的导航控制器进行跳转。也就是说Q的关于控制器的操作都被P给处理了。
那新加入一个问题:如果在Q中present出来一个界面R,那这个R的presentingViewController是谁呢?
是的,是P。此时已经出现了刚才说的问题,Q打开了R,但是R的presentingViewController却是P。这时因为Q是P的子控制器。
那么就可以解释上面两个图片的结果为什么是navi控制器和tabbar控制器了。因为使用标签控制器和导航控制器,都是显示的子控制器的内容,一个带导航栏,一个带标签栏。
所有的控制器都有childViewControllers属性,保存了所有的子控制器,但是有些特殊的控制器,比如UIPageViewController、UINavigationController、UITabBarController等,还有一个viewControllers属性,实际内容和childViewControllers一样。这些特殊的控制器实际上不展示主要内容,主要内容由子控制器展示。
所以刚才说,只要你学了UIKit用了UINavigationController和UITabBarController,你就在使用childViewControllers在做界面的管理了。
因此,当某个控制器有父控制器的时候,它的presentingViewController是父控制器的presentingViewController。
说这么多,又有毛用?
image.png
比如你做过转场动画,会用到这么个方法animateTransition(using transitionContext: UIViewControllerContextTransitioning),当然你首先要做的,就是从context里获取toViewcontroller和fromViewController。如果你的这个转场是个modalPresent,此时你获取到的fromViewController可不一定是调用present的那个控制器,所以你要根据这个VC来做一些动画,可能就要有问题了。
如果是带UINavigationController,需要通过nav.topViewController获取nav当前的控制器,如果是带UITabBarController,需要通过tab.selectedViewController获取tab当前的控制器。
四、如何强制指定presentingViewController就是打开自己的那个?
我们需要了解一下这两个属性:
@property(nonatomic,assign) BOOL definesPresentationContext;
@property(nonatomic,assign) UIModalPresentationStyle modalPresentationStyle;
modalPresentationStyle属性决定了将要present的控制器以何种方式展现,默认值为UIModalTransitionStyleCoverVertical。如果把一个控制器的definesPresentationContext属性设置为YES,那么在需要进行UIModalPresentationCurrentContext类型的跳转的时候,UIKit会使用视图层级内的这个控制器来进行跳转。
avc.definesPresentationContext = false
avc.modalPresentationStyle = .currentContext
大功告成!现在presentingViewController能够获取到我们期望的对象了。
dismiss和remove_你真的了解iOS中控制器的present和dismiss吗?相关推荐
- iOS中控制器的实践和学习(2)-认识XCode4模版(A1,A3,B2简易图)
这里先看下XCode4下有哪些可创建的应用程序模版,如下图: 看,标记了A1.A3.B2的3个应用模版,对应是上节所画的简易图的标记. 就是说,创建这3类模版,编译运行,就和简易图效果是一致的. 至于 ...
- ios注销所有通知_您一直想了解的有关iOS中通知的所有信息
ios注销所有通知 by Payal Gupta 通过Payal Gupta 您一直想了解的有关iOS中通知的所有信息 (Everything you've always wanted to know ...
- 你真的了解iOS怎么取属性的吗?
你真的了解iOS怎么取属性的吗? 本文来自CocoaChina粉丝FlyOceanFish投稿 如果iOS中谈到取属性,相信大家都会夸夸其谈,不就是get方法吗?或者大谈kvc取属性的机制.不得不说这 ...
- 浅谈iOS中的蓝牙技术(一) GameKit framework
蓝牙低能耗(BLE)技术是低成本.短距离.可互操作的无线技术,工作在免许可的2.4GHz ISM射频频段. Start GameKit.framework 只能用于iOS设备之间的同个应用内连接,多用 ...
- 关于iOS中MVC和MVVM的区别和联系
MVC 的历史 MVC,全称是 Model View Controller,是模型 (model)-视图(view)-控制器 (controller) 的缩写.它表示的是一种常见的客户端软件开发框架. ...
- 关于 iOS 中 new Date()的坑
这个坑弄了我一上午,真的是醉了. 首先是一个H5页面,要在微信中推广,当我 new Date()的时候在iOS中就会出现Date无效,这就尴尬了,找了好多也没找到.一般标准时间都是YYYY-MM-DD ...
- 浅谈iOS中关于app的优化
目录 我要给出的建议将分为三个不同的等级: 入门级. 中级和进阶级: 入门级(这是些你一定会经常用在你app开发中的建议) 1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier ...
- ios html格式转换,如何使用HTML模版和iOS中的UIPrintPageRenderer来生成PDF文档
如何使用HTML模版和iOS中的UIPrintPageRenderer来生成PDF文档 作者:GABRIEL THEODOROPOULOS,时间:2016/7/10 翻译:BigNerdCoding, ...
- php ios android 加密,在android/ios中加密,在php中解密
我想解密我的网站上的一个字符串,该字符串在移动设备(Android或ios)上加密. 我有一个类似的输出,从这两个设备,它使用以下Android代码(sans例外保持简短).在android/ios中 ...
- iOS中解析json数据
同Android中的jsonarray和jsonobject相同,iOS中json分为nsarray和jsonobject, []--------jsonarray/nsarray; {}------ ...
最新文章
- Linux内核网络数据发送(六)——网络设备驱动
- 湘财证券罗叶:数字化在金融领域的应用与实践,从“我觉得”到“用户觉得”...
- 第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波10 - 直方图处理 - 局部直方图处理
- 怎么批量修改html文件后缀,怎么批量修改文件后缀
- 判断设置两天后时间,时间戳
- MongoDB:MapReduce基础及实例
- mysql之多表联合查询并输入数据来自哪张表
- 天声人語2008年05月04日-蔬菜的阴谋
- 北风网厉风行Java设计模式视频观后总结
- 解析信号与希尔伯特变换
- window双开微信
- 美图秀秀各插件适用场景
- 函数间断点类型及其判别方法
- Qt setStyleSheet 透明图片叠加
- Satellite7 v2.4 WordPress扁平化风格主题
- DSP 性能 GMAC 和 GFLOP含义
- 高等概率论 Chapter 6 Construction of a Probability Measure
- 这样弄简历就算面试过了,offer也会黄!
- 软考高级-信息系统管理师之项目管理基础(最新版)
- DiscuzX3.1数据库字典(含之前)
热门文章
- php 足迹 表设计,成长的足迹设计方案
- 使用Scrum敏捷开发 —实现多维度碎片化迭代
- C++几个常用的排序
- Delphi 编译的程序在win10中怎样默认以管理员身份运行
- DBeaver 安装及配置离线驱动
- Oracle 星期(周末处理)
- JS编程建议——16:防止switch贯穿
- 清华大学生计算机系学生就业方向,这5所大学计算机专业全球顶尖,就业前景广阔,毕业就能拿高薪!...
- Pygame实战之外星人入侵NO.5——操作子弹
- linux 无线网卡 频段,Linux 网卡配置 (频段、发射功率等)