当UINavigationController执行事务时发生崩溃

时间:2014-07-16 20:22:38

标签: ios objective-c uinavigationcontroller

我刚看到一个崩溃显示如下屏幕截图,当我点击导航栏上的后退按钮时,是否有任何典型情况会导致此次崩溃?

enter image description here

1 个答案:

答案 0 :(得分:2)

根据我的经验,iOS 7中引入了一个问题,使您可以在另一个结束之前启动转换,最终导致此崩溃。如果您将2个导航调用重新放回并运行它们,则可以手动重现此操作,例如:

[self.navigationController pushViewController:whatever animated:YES];
[self.navigationController pushViewController:whatever2 animated:YES];

如果你这样做,你最终会看到崩溃。

我发现确保永远不会发生这种情况的最简单方法是通过继承UINavigationController并实施UINavigationControllerDelegate来防止重叠转换。

一旦我开始使用下面的代码,由于此问题我看到的崩溃次数已降至0。

需要注意的一点是,如果您确实需要实现另一个<UINavigationControllerDelegate>,则需要编写一些代码来自行存储额外的委托并传递委托调用,可能使用NSProxy或其他东西那样的。

@interface MyNavigationController () <UINavigationControllerDelegate>
{
    // used to prevent "can't add self as subview" crashes which occur when trying to animate 2 transitions simultaneously
    BOOL _currentlyAnimating;
}

@end

@implementation MyNavigationController

- (void) viewDidLoad
{
    [super viewDidLoad];
    self.delegate = self;
}

- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if(_currentlyAnimating)
    {
        return;
    }
    else if(animated)
    {
        _currentlyAnimating = YES;
    }

    [super pushViewController:viewController animated:animated];
}

- (UIViewController *) popViewControllerAnimated:(BOOL)animated
{
    if(_currentlyAnimating)
    {
        return nil;
    }
    else if(animated)
    {
        _currentlyAnimating = YES;
    }

    return [super popViewControllerAnimated:animated];

}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    _currentlyAnimating = NO;
}

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // tracking cancelled interactive pop
    // http://stackoverflow.com/questions/23484310/canceling-interactive-uinavigationcontroller-pop-gesture-does-not-call-uinavigat
    [[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context)
    {
        if([context isCancelled])
        {
            UIViewController *fromViewController = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
            [self navigationController:navigationController willShowViewController:fromViewController animated:animated];

            if([self respondsToSelector:@selector(navigationController:didShowViewController:animated:)])
            {
                NSTimeInterval animationCompletion = [context transitionDuration] * [context percentComplete];

                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t)animationCompletion * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
                    [self navigationController:navigationController didShowViewController:fromViewController animated:animated];
                });
            }


        }
    }];
}

@end