背景:登錄注冊界面有控制器A、B、C,登錄后切換根視圖為主頁D
切換根視圖C->D的時候,我直接用的下面這句代碼
[UIApplication sharedApplication].delegate.window.rootViewController = [ViewControllerD new];
發現沒有進入A、B、C相應的dealloc方法,就是說控制器A、B、C并沒有被釋放。檢查后發現是因為我切換根視圖控制器前,忘了dismiss控制器A、B、C。
該怎么dismiss掉3個控制器呢?
百度查到:通過self.presentingViewController可以獲取到當前控制器的父控制器,self.presentingViewController.presentingViewController獲取父父控制器 and so on...,所以我們需要通過代理或者通知來一層層的dismiss嗎?很顯然這并不是一個好方法。
這篇文章提供了新的思路 ios 如何dismiss連續好幾個viewControllers:
查了蘋果官網發現:
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.
大致就是如果您連續彈出幾個視圖控制器,從而為這些彈出的視圖控制器建立一個堆棧,調用dismissViewControllerAnimated:completion:這個方法去解散其他的視圖控制器。僅僅是最頂層是被解散,中間的視圖控制器從棧中刪除了。
并且文中提供了用代理或者通知去dismiss最頂層控制器的方法,但是我覺得有些麻煩,既然可以獲取到父控制器,應該可以用循環實現,所以我用while循環實現如下:
//把最底部的視圖控制器dismiss掉
UIViewController *parentVC = self.presentingViewController;
UIViewController *bottomVC;
while (parentVC) {
bottomVC = parentVC;
parentVC = parentVC.presentingViewController;
}
[bottomVC dismissViewControllerAnimated:NO completion:nil];
[UIApplication sharedApplication].delegate.window.rootViewController = [ViewControllerD new];
這樣就可以在當前視圖中dismiss最底部控制器了,并且進入dealloc方法A、B、C控制器都銷毀了.(如果我這樣寫有問題歡迎指出)
但是發現了新的問題
由于D中沒有任何東西,甚至連背景色都沒添加!所以在切換根視圖控制器后,發現D視圖上居然顯示出最底部A視圖的界面!再確認根控制器確實是D并且A、B、C都進入dealloc中銷毀掉后,WTF ?視圖銷毀后它的視圖不應該就沒有了嗎,實在是想不通。
效果圖如下
開始我以為是代碼寫的有問題視圖沒有被釋放掉,后來新建一個項目專門這樣切換根視圖,發現有同樣的問題,反復試驗后發現:
- 如果我在D上添加了背景色或者view,它就會把A視圖的view給擋住;
- 如果只有一個控制器A,直接從A切換根視圖到D,那么不會出現這種問題,甚至切換根視圖前都不用dismiss掉A,但如果有A->B多個的話就會出現我這種問題;
- D上顯示的 A中view的約束會出錯;
- D上顯示的 A中的button是不可點擊的;
這樣寫可以達到效果
百思不得其解后,最終我把目光投到了 [dismissViewControllerAnimated: completion:] 方法的completion block中,我是想在視圖dismiss完成后再切換根視圖,所以我把切換根視圖的操作放到了 dismiss的completion塊中:
//把最前面的視圖控制器dismiss掉
UIViewController *parentVC = self.presentingViewController;
UIViewController *bottomVC;
while (parentVC) {
bottomVC = parentVC;
parentVC = parentVC.presentingViewController;
}
[bottomVC dismissViewControllerAnimated:NO completion:^{
//dismiss后再切換根視圖
[UIApplication sharedApplication].delegate.window.rootViewController = [TabBarController new];
}];
return;
將dismiss動畫Animated設置為NO,發現這樣可以達到效果;
我不知道為什么會出現A控制器銷毀后還會在根視圖D上保持顯示這種現象,如果有人知道歡迎告訴我~
另外,如果dismiss動畫設置為YES,會神奇的發現根視圖切換為D時,能看到C(藍色)、B(黃色)、A(紅色)依次消失:
補充:如果是UINavigationController
今天看MJRefresh的demo,其中使用的是UINavigationController來push控制器,發現demo中切換根視圖時沒有進行pop操作,導航控制器棧內的所有控制器都dealloc被釋放了。然后我試驗了下的確如此,雖然我不明白為啥模態和導航控制器,同樣是根視圖的引用被切換釋放了,卻產生不同效果。我猜測可能是導航控制器和模態跳轉的一個不同吧... 以后有多層跳轉后切換根視圖就盡量用導航控制器去做了。