咱们都知道dismissViewControllerAnimated:completion:
方法是针对被present出来的控制器的,通常咱们这样使用:在一个控制器中present另一个控制器A,而后在A中执行dismissViewControllerAnimated:completion:
让本身消失。app
在ViewController中:动画
AViewController *av = [[AViewController alloc]init]; UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:av]; [self presentViewController:nav animated:YES completion:nil];
在AViewController中执行disimiss:ui
[self dismissViewControllerAnimated:YES completion:nil];
对于这种很常见的场景,这种用法彻底没问题。可是对于复杂一点的场景,这种用法就有点苍白无力了,先举个稍微复杂一点点的例子:ViewController present AViewController,AViewController present BViewController,在BViewController执行完某事件以后须要返回ViewController。这个时候须要怎样作呢?若是在BViewController直接执行的话,它只会将BViewController消失。[self dismissViewControllerAnimated:YES completion:nil];
这里你可能会想到经过其余方式拿到AViewController,而后调用AViewController的[self dismissViewControllerAnimated:YES completion:nil];
。可是,场景再复杂一点,在执行完各类present和push以后,到达了XViewController,在XViewController中执行成功任务以后须要回到ViewController,这个时候怎么办呢?咱们知道当前若是有被present出来的控制器的状况下,调用UINavigationController的popToRootViewControllerAnimated:
是不起做用的。那么咱们如何把这个流程中全部被present和push的控制器给销毁呢?笨一点的办法是回溯整个流程,判断哪些控制器须要dismiss,哪些控制器须要pop。但这种方式显然有点低效和难以控制,下面咱们来看看到底该怎么使用dismissViewControllerAnimated:completion:
。this
咱们先看看官方文档到底怎么讲的:spa
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.code
能够简单概括为两点:blog
第一点:谁present出来的控制器,谁负责把它dismiss掉,可是若是你在被present出来的控制器中调用dismiss的话,UIKit会自动让它的presenting控制器(找到谁把它present出来的)去执行dismiss。事件
第二点:若是你present了一系列的控制器,那么系统会把被present出来的控制器放在一个栈中,当处在底层的控制器执行dismiss的时候,在它以后被present出来的控制器都会被移除,只有栈顶上的控制器会有dismiss动画。rem
另外补充相关的两点:文档
第一点:当被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]
的流程是这样子的:
在咱们上面讲的复杂场景下,咱们怎么一次性把当前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]; }