2011-03-14 126 views
49

我一直在尋找一個解決方案的互聯網。我找不到任何東西。因此: 我使用的是UINavigationController。我推着兩個UIViewControllers。在第二個推視圖控制器我執行此代碼:iOS:popViewController意外行爲

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error { 
NSLog([error localizedDescription]); 
[self.navigationController popViewControllerAnimated:YES]; } 

預期發生的事情將是最後推送的ViewController消失。在這個應用程序中,我在少數幾個地方這樣做,它在任何期望的ViewController中都能正常工作。 會發生什麼情況是隻有後退按鈕熄滅屏幕(動畫),但其他所有內容都保留在屏幕上。在控制檯輸出兩件事情都打印出來時這個行執行:

2011-03-14 16:32:44.580 TheAppXY [18518:207]嵌套彈出 動畫可導致損壞 導航欄

2011-03-14 16:32:53.507 TheAppXY [18518:207]以意想不到的 狀態完成導航轉換。導航欄子視圖樹 可能會損壞。

兩條錯誤消息我找不到任何信息。 我正在使用XCode 4和iOS SDK 4.3。也許任何人都可以幫助我解決這個問題。

+1

我想我自己想通了。我認爲這是因爲我試圖過早地彈出視圖控制器。如果反向地理編碼器提供了一個地址(該地址在ViewDidLoad中啓動)並且失敗,那麼該視圖還沒有出現,所以動畫彈出不太明顯。我現在在ViewDidAppear中實現了Reverse Geocoder的開始,並且一切似乎都正常。新手錯誤或多或少。但我不知道有沒有關於它的信息 – Christoph 2011-03-14 16:18:22

+0

最近,我遇到了同樣的問題。原因是: - 我試圖錯誤地彈出視圖控制器兩次。你可以通過在push和pop上設置斷點來檢查這個崩潰。視圖控制器 – 2014-07-31 09:07:47

回答

28

您可以在任何時候嘗試在viewDidAppear之前彈出。如果你設置了一個標誌,那麼只需在viewDidAppear中檢查該標誌,你就不會有問題。

+0

這似乎是最安全的方法 – Dmytro 2016-03-24 22:09:05

50

我遇到類似的情況在我的代碼來了,留言說:可能導致損壞的導航欄

整理了意外狀態導航過渡

嵌套推動畫。導航欄子視圖樹>可能會損壞。

我對這個問題的發現是,我一個接一個地連續推動2個視圖控制器,並且都是動畫的。

在你的情況,似乎你可能會彈出多個視圖控制器與動畫一個接一個。

因此,當一個視圖正在進行動畫時,您不應該在另一個視圖上啓動動畫。

我還發現,如果我在一個視圖上禁用了動畫,錯誤消息就消失了。

在我的情況下,這是一個流邏輯的問題,因爲我不打算一個接一個地推動2個視圖控制器。一個人在開關櫃邏輯中被推入,另一個在結束後被推入。

希望這可以幫助別人。

+10

他們在這裏輸入的關鍵字是:「...並且都是動畫。」謝謝! – 2011-08-05 17:58:14

+0

您是否有任何建議來處理您希望這樣做的情況?例如,當我將視圖控制器推入堆棧時,我會看到很多,然後顯示一個UIAlertView。我仍然想要展示他們兩個,我只是希望View被推入堆棧,然後顯示alert視圖而不必實現一堆委託方法。 – dsingleton 2012-06-08 20:48:34

+3

感謝當我更改爲'Animated:YES'到'Animated:NO'並且在'viewDidAppear'上調用我的pop方法時,感謝解決了問題 – 2012-11-02 15:39:47

3

我有這個問題,也和這裏是什麼導致我的:

  1. 在RootViewController的,我用幾個UISegmentedControl對象以確定其中許多意見旁加載。
  2. 在那個(sub/2nd)視圖中,我彈出(通過使用「返回」按鈕)回到RootViewController。
  3. 在RootViewController中,我正在處理viewWillAppear以將每個UISegmentedControl對象「重置」爲-1的selectedSegmentIndex(意味着沒有看起來像「按下」的段)。
  4. 「重置」觸發我的每個UISegmentedControl對象觸發其關聯(和單獨)的IBActions。
  5. 因爲我沒有處理-1的「選擇」,所以我有多個方法在同一時間觸發,所有嘗試推入不同的視圖。

我的修復?我收緊了我的if ... then語句,並在selectedSegmentIndex == -1時保留在我的UISegmentedControl IBActions中執行任何代碼。

我仍然不確定爲什麼我會彈出動畫錯誤,而不是「推」錯誤,但至少弄清了我的錯誤並修復了錯誤!

希望這可以幫助別人!

12

我已經爲UINavigationController創建了一個替代插件,它將爲您排隊動畫並完全避免此問題。

抓住它從BufferedNavigationController

+0

嘿安德魯,你還支持上面的課嗎?由於某種原因,它不適合我,因爲你可以在這裏看到:http://stackoverflow.com/questions/16634337/right-to-left-push-animation-results-in-corrupted-navigation-bar – Segev 2013-05-19 17:10:04

+0

另請參見我的UINavigationControllerWithQueue回答下面,替代 – MarkWPiper 2015-06-20 07:34:40

0

是啊,可惜的是蘋果沒有同步的UINavigationController的動畫。安德魯的解決方案是優秀的,但如果你不想支付其全部的功能,有一個簡單的解決方案,覆蓋這兩種方法:

// navigation end event 

- (void) navigationController : (UINavigationController*) pNavigationController 
      didShowViewController : (UIViewController*  ) pController 
      animated    : (BOOL     ) pAnimated 
{ 

    if ([ waitingList count ] > 0) [ waitingList removeObjectAtIndex : 0 ]; 
    if ([ waitingList count ] > 0) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ]; 

} 


- (void) pushViewController : (UIViewController*) pController 
      animated   : (BOOL) pAnimated 
{ 

    [ waitingList addObject : pController ]; 
    if ([ waitingList count ] == 1) [ super pushViewController : [ waitingList objectAtIndex : 0 ] animated : YES ]; 

} 

並創建一個名爲waitingList一個NSMutableArray實例變量,和你做。

+0

我接受了這個想法,並將其推廣到以下答案中的popViewController *,UINavigationControllerWithQueue – MarkWPiper 2015-06-20 07:37:08

0

當我使用故事板時,這個問題發生在我身上。我犯了一個錯誤: 我有一個UIButton執行SegueWithIdentifier的動作。所以我把push segue與Button和另一個ViewController聯繫起來,所以發生這個問題。

解決方法: 鏈接UIButton中的按鈕動作並鏈接兩個ViewController之間的push segue。

0

結合MilGra和Andrew的回答給了我一些可靠工作的東西,並且是一個更簡單的插入式UINavigationController替換。

這改進了MilGra的答案,使其能夠處理推送和彈出,但比Andrew的BufferedNavigationController更簡單。 (使用BufferedNavigationController我偶爾會得到永遠不會完成的轉換,只會顯示黑屏。)

這整個事情似乎沒有必要在iOS8上,但仍然需要我在iOS7上。

@implementation UINavigationControllerWithQueue { 
    NSMutableArray *waitingList; 
} 

-(void) viewDidLoad { 
    [super viewDidLoad]; 
    self.delegate = self; // NOTE: delegate must be self! 
    waitingList = [[NSMutableArray alloc] init]; 
} 

# pragma mark - Overrides 

-(void) pushViewController: (UIViewController*) controller 
        animated: (BOOL) animated { 
    [self queueTransition:^{ [super pushViewController:controller animated:animated]; }]; 
} 

- (UIViewController *)popViewControllerAnimated:(BOOL)animated { 
    UIViewController *result = [self.viewControllers lastObject]; 
    [self queueTransition:^{ [super popViewControllerAnimated:animated]; }]; 
    return result; 
} 

- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated { 
    NSArray* results = [self.viewControllers copy]; 
    [self queueTransition:^{ [super popToRootViewControllerAnimated:animated]; }]; 
    return results; 
} 

# pragma mark - UINavigationControllerDelegate 

-(void) navigationController: (UINavigationController*) navigationController 
     didShowViewController: (UIViewController*) controller 
        animated: (BOOL) animated { 
    [self dequeTransition]; 
} 

# pragma mark - Private Methods 

-(void) queueTransition:(void (^)()) transition { 
    [waitingList addObject:transition]; 
    if (waitingList.count == 1) { 
     transition(); 
    } 
} 

-(void) dequeTransition { 
    if (waitingList.count > 0) { 
     [waitingList removeObjectAtIndex:0]; 
    } 
    if (waitingList.count > 0) { 
     void (^transition)(void) = [waitingList objectAtIndex:0]; 
     if (transition) { 
      transition(); 
     } 
    } 
} 

@end 
+0

在模擬器中工作得很好,但在設備上不可靠 - 所以最終不是推薦的方法。 – MarkWPiper 2015-07-13 18:04:21