iOS dismissViewControllerAnimated:completion:使用方法

咱們都知道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];
}
相關文章
相關標籤/搜索