【发布时间】:2014-07-16 20:22:37
【问题描述】:
我刚刚遇到如下截图所示的崩溃,当我点击导航栏上的返回按钮时发生了这种情况,是否有任何典型情况会导致这种崩溃?
【问题讨论】:
标签: ios objective-c uinavigationcontroller
我刚刚遇到如下截图所示的崩溃,当我点击导航栏上的返回按钮时发生了这种情况,是否有任何典型情况会导致这种崩溃?
【问题讨论】:
标签: ios objective-c uinavigationcontroller
根据我的经验,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
【讨论】: