dismissViewControllerAnimated:completion:你用对了吗?

我们都知道dismissViewControllerAnimated:completion:方法是针对被present出来的控制器的,一般我们这样使用:在一个控制器中present另外一个控制器A,然后在A中执行dismissViewControllerAnimated:completion:让自己消失。

在ViewController中:

AViewController *av = [[AViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:av];
[self presentViewController:nav animated:YES completion:nil];

在AViewController中执行disimiss:

[self dismissViewControllerAnimated:YES completion:nil];

对于这种很常见的场景,这种用法完全没问题。但是对于复杂一点的场景,这种用法就有点苍白无力了,先举个稍微复杂一点点的例子:ViewController present AViewController,AViewController present BViewController,在BViewController执行完某事件之后需要返回ViewController。这个时候需要怎样做呢?如果在BViewController直接执行[self dismissViewControllerAnimated:YES completion:nil];的话,它只会将BViewController消失。

这里你可能会想到通过其他方式拿到AViewController,然后调用AViewController的[self dismissViewControllerAnimated:YES completion:nil];。但是,场景再复杂一点,在执行完各种present和push之后,到达了XViewController,在XViewController中执行成功任务之后需要回到ViewController,这个时候怎么办呢?我们知道当前如果有被present出来的控制器的情况下,调用UINavigationController的popToRootViewControllerAnimated:是不起作用的。那么我们如何把这个流程中所有被present和push的控制器给销毁呢?笨一点的办法是回溯整个流程,判断哪些控制器需要dismiss,哪些控制器需要pop。但这种方式显然有点低效和难以控制,下面我们来看看到底该怎么使用dismissViewControllerAnimated:completion:

我们先看看官方文档到底怎么讲的:

Dismisses the view controller that was presented modally by the view controller.
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.

可以简单归纳为两点:

第一点:谁present出来的控制器,谁负责把它dismiss掉,但是如果你在被present出来的控制器中调用dismiss的话,UIKit会自动让它的presenting控制器(找到谁把它present出来的)去执行dismiss。

第二点:如果你present了一系列的控制器,那么系统会把被present出来的控制器放在一个栈中,当处在底层的控制器执行dismiss的时候,在它之后被present出来的控制器都会被移除,只有栈顶上的控制器会有dismiss动画。

另外补充相关的两点:

第一点:当被present出来的控制器的modalPresentationStyle = UIModalPresentationFullScreen时,执行当前present事件的控制器必须是一个全屏控制器,如果当前执行的控制器不是一个全屏的控制器,它将在视图层级结构中找到一个全屏的父类控制器去执行present事件。也就是说如果A 执行present B,那么B.presentingViewController不一定是A。比如你当前的控制器A在导航nav中,A present B之后,实际上B.presentingViewController指向的是nav而不是A。

第二点:self.presentingViewController,它指向的是把当前控制器present出来的控制器或者是把当前控制器的最上层的父类present出来的控制器。

通过上面的文档介绍,我们可以看到在本文刚开始介绍的最简单的使用场景下(ViewController present AViewController),在AViewController中执行[self dismissViewControllerAnimated:YES completion:nil]和在ViewController中执行[self dismissViewControllerAnimated:YES completion:nil]效果是一样的,这一点是因为系统帮我们处理好了(因为系统判断AViewController当前没有present出来任何控制器,所以系统会找到它的presentingViewController,也就是ViewController来执行dismiss事件)。在复杂一点的情况下,比如我们要dismiss掉当前被present出来的控制器的话,我们就需要想办法拿到处在栈底的那个控制器,在这个控制器中执行[self dismissViewControllerAnimated:YES completion:nil]才行。

那么很显然,执行[self dismissViewControllerAnimated:YES completion:nil]的流程是这样子的:

dimiss_process.png

在我们上面讲的复杂场景下,我们怎么一次性把当前present出来的控制都dismiss掉呢?可以通过下面的方式来查找到最顶层的presentingViewController(其实,通常是我们window的rootViewController)让它来执行dismiss就好了,剩下的工作可能就是处理一下导航中的控制器了。

比如我们在经过各种present和push之后才到达的XViewController页面中执行如下代码:

UIViewController *presentingVc = self.presentingViewController;
while (presentingVc.presentingViewController) {
    presentingVc = vc.presentingViewController;
}
if(presentingVc){
    [presentingVc dismissViewControllerAnimated:YES completion:nil];
}

转载请注明出处,欢迎关注支持微信公众号“猿故”!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,817评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,329评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,354评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,498评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,600评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,829评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,979评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,722评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,189评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,519评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,654评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,940评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,762评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,993评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,382评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,543评论 2 349

推荐阅读更多精彩内容