一、了解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吗?相关推荐

  1. iOS中控制器的实践和学习(2)-认识XCode4模版(A1,A3,B2简易图)

    这里先看下XCode4下有哪些可创建的应用程序模版,如下图: 看,标记了A1.A3.B2的3个应用模版,对应是上节所画的简易图的标记. 就是说,创建这3类模版,编译运行,就和简易图效果是一致的. 至于 ...

  2. ios注销所有通知_您一直想了解的有关iOS中通知的所有信息

    ios注销所有通知 by Payal Gupta 通过Payal Gupta 您一直想了解的有关iOS中通知的所有信息 (Everything you've always wanted to know ...

  3. 你真的了解iOS怎么取属性的吗?

    你真的了解iOS怎么取属性的吗? 本文来自CocoaChina粉丝FlyOceanFish投稿 如果iOS中谈到取属性,相信大家都会夸夸其谈,不就是get方法吗?或者大谈kvc取属性的机制.不得不说这 ...

  4. 浅谈iOS中的蓝牙技术(一) GameKit framework

    蓝牙低能耗(BLE)技术是低成本.短距离.可互操作的无线技术,工作在免许可的2.4GHz ISM射频频段. Start GameKit.framework 只能用于iOS设备之间的同个应用内连接,多用 ...

  5. 关于iOS中MVC和MVVM的区别和联系

    MVC 的历史 MVC,全称是 Model View Controller,是模型 (model)-视图(view)-控制器 (controller) 的缩写.它表示的是一种常见的客户端软件开发框架. ...

  6. 关于 iOS 中 new Date()的坑

    这个坑弄了我一上午,真的是醉了. 首先是一个H5页面,要在微信中推广,当我 new Date()的时候在iOS中就会出现Date无效,这就尴尬了,找了好多也没找到.一般标准时间都是YYYY-MM-DD ...

  7. 浅谈iOS中关于app的优化

    目录 我要给出的建议将分为三个不同的等级: 入门级. 中级和进阶级: 入门级(这是些你一定会经常用在你app开发中的建议) 1. 用ARC管理内存 2. 在正确的地方使用reuseIdentifier ...

  8. ios html格式转换,如何使用HTML模版和iOS中的UIPrintPageRenderer来生成PDF文档

    如何使用HTML模版和iOS中的UIPrintPageRenderer来生成PDF文档 作者:GABRIEL THEODOROPOULOS,时间:2016/7/10 翻译:BigNerdCoding, ...

  9. php ios android 加密,在android/ios中加密,在php中解密

    我想解密我的网站上的一个字符串,该字符串在移动设备(Android或ios)上加密. 我有一个类似的输出,从这两个设备,它使用以下Android代码(sans例外保持简短).在android/ios中 ...

  10. iOS中解析json数据

    同Android中的jsonarray和jsonobject相同,iOS中json分为nsarray和jsonobject, []--------jsonarray/nsarray; {}------ ...

最新文章

  1. Linux内核网络数据发送(六)——网络设备驱动
  2. 湘财证券罗叶:数字化在金融领域的应用与实践,从“我觉得”到“用户觉得”...
  3. 第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波10 - 直方图处理 - 局部直方图处理
  4. 怎么批量修改html文件后缀,怎么批量修改文件后缀
  5. 判断设置两天后时间,时间戳
  6. MongoDB:MapReduce基础及实例
  7. mysql之多表联合查询并输入数据来自哪张表
  8. 天声人語2008年05月04日-蔬菜的阴谋
  9. 北风网厉风行Java设计模式视频观后总结
  10. 解析信号与希尔伯特变换
  11. window双开微信
  12. 美图秀秀各插件适用场景
  13. 函数间断点类型及其判别方法
  14. Qt setStyleSheet 透明图片叠加
  15. Satellite7 v2.4 WordPress扁平化风格主题
  16. DSP 性能 GMAC 和 GFLOP含义
  17. 高等概率论 Chapter 6 Construction of a Probability Measure
  18. 这样弄简历就算面试过了,offer也会黄!
  19. 软考高级-信息系统管理师之项目管理基础(最新版)
  20. DiscuzX3.1数据库字典(含之前)

热门文章

  1. php 足迹 表设计,成长的足迹设计方案
  2. 使用Scrum敏捷开发 —实现多维度碎片化迭代
  3. C++几个常用的排序
  4. Delphi 编译的程序在win10中怎样默认以管理员身份运行
  5. DBeaver 安装及配置离线驱动
  6. Oracle 星期(周末处理)
  7. JS编程建议——16:防止switch贯穿
  8. 清华大学生计算机系学生就业方向,这5所大学计算机专业全球顶尖,就业前景广阔,毕业就能拿高薪!...
  9. Pygame实战之外星人入侵NO.5——操作子弹
  10. linux 无线网卡 频段,Linux 网卡配置 (频段、发射功率等)