iOS:popViewController意外行为

时间:2011-03-14 15:51:27

标签: xcode ios uinavigationcontroller

我一直在网上寻找解决方案。我找不到任何东西。 所以: 我正在使用UINavigationController。我正在推动两个UIViewControllers。在第二个推送的ViewController中,我正在执行此代码:

- (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]嵌套pop   动画可能会导致损坏   导航栏

     

2011-03-14 16:32:53.507   TheAppXY [18518:207]完成了一个   意外的导航过渡   州。导航栏子视图树   可能会被破坏。

两条错误消息我找不到任何关于的信息。 我正在使用XCode 4和iOS SDK 4.3。也许任何人都可以帮我解决这个问题。

7 个答案:

答案 0 :(得分:50)

我在我的代码中遇到了类似的情况,并且消息说:

  

嵌套推送动画可能导致导航栏损坏

     

在意外状态下完成导航转换。导航栏子视图树>可能会损坏。

我对这个问题的发现是我一个接一个地连续推动2个视图控制器,并且都是动画的。

在你的情况下,似乎你可能会一个接一个地弹出多个带有动画的视图控制器。

因此,当一个视图正在进行动画时,您不应该在另一个视图上开始动画。

我还发现,如果我在一个视图上禁用动画,则错误消息会消失。

在我的情况下,流逻辑存在问题,因为我不打算一个接一个地推送2个视图控制器。其中一个被推入开关盒逻辑,另一个被推到结束后。

希望这有助于某人。

答案 1 :(得分:28)

您可以在viewDidAppear之前尝试弹出时随时获取此信息。如果您设置了一个标志,那么只需在viewDidAppear中检查该标志,就不会有问题。

答案 2 :(得分:12)

我已经为UINavigationController创建了一个替代品,它会为你排队动画并完全避免这个问题。

BufferedNavigationController

抓取

答案 3 :(得分:3)

我也有这个问题,这就是导致我的问题:

  1. 在RootViewController中,我使用了几个UISegmentedControl对象来确定下一个要加载的视图中的哪一个。
  2. 在那个(子/第二)视图中,我弹出(通过使用“Back”按钮)回到RootViewController。
  3. 在RootViewController中,我正在处理viewWillAppear以将我的每个UISegmentedControl对象“重置”为selectedSegmentIndex为-1(意味着没有任何段看起来“按下”)。
  4. “重置”触发了我的每个UISegmentedControl对象以触发其关联的(和单独的)IBActions。
  5. 由于我没有处理-1的“选择”,我有多个方法同时触发,都试图推动不同的视图。
  6. 我的修复?当selectedSegmentIndex == -1时,我收紧了if ... then语句,并在我的UISegmentedControl IBActions中执行任何代码。

    我仍然不确定为什么我会出现“pop”动画错误而不是“推”错误,但至少弄明白了我的错误并修复了它!

    希望这有助于其他人!

答案 4 :(得分: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实例变量,您就完成了。

答案 5 :(得分:0)

当我使用故事板时,这个问题发生在我身上。我犯了一个错误: 我有一个UIButton,有一个动作来执行SegueWithIdentifier。所以我将push segue与Button与另一个ViewController链接起来,所以出现了这个问题。

要解决: 链接UIButton中的按钮操作,并链接两个ViewControllers之间的push segue。

答案 6 :(得分: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