iOS:popViewController 意外行为
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5301014/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS: popViewController unexpected behavior
提问by Christoph
I've been searching the internet for a solution. There's nothing I could find. So: I'm using a UINavigationController. I am pushing two UIViewControllers onto it. In the second pushed ViewController i am executing this code:
我一直在互联网上寻找解决方案。我什么都找不到。所以:我正在使用 UINavigationController。我将两个 UIViewControllers 推到它上面。在第二个推送的 ViewController 中,我正在执行此代码:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
NSLog([error localizedDescription]);
[self.navigationController popViewControllerAnimated:YES]; }
The expected thing to happen would be that the last pushed ViewController disappears. In this app I am doing this on few places and it works fine everywhere expect in this very ViewController. What happens is that only the back button goes off screen (animated) but everything else stays on screen. In the Console Output two things are printed out when this line executes:
预期发生的事情是最后推送的 ViewController 消失了。在这个应用程序中,我在几个地方这样做,它在这个 ViewController 中的任何地方都可以正常工作。发生的情况是只有后退按钮离开屏幕(动画),但其他所有内容都保留在屏幕上。在控制台输出中,当此行执行时会打印出两件事:
2011-03-14 16:32:44.580 TheAppXY[18518:207] nested pop animation can result in corrupted navigation bar
2011-03-14 16:32:53.507 TheAppXY[18518:207] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
2011-03-14 16:32:44.580 TheAppXY[18518:207] 嵌套的流行动画会导致导航栏损坏
2011-03-14 16:32:53.507 TheAppXY[18518:207] 在意外状态下完成导航转换。导航栏子视图树可能会损坏。
Two error messages I couldn't find ANY information on. I'm using XCode 4 and iOS SDK 4.3. Maybe anyone can help me with this problem.
两条错误消息我找不到任何信息。我正在使用 XCode 4 和 iOS SDK 4.3。也许任何人都可以帮助我解决这个问题。
回答by Vishal Chaudhry
I came across a similar situation in my code and the message said:
我在我的代码过类似的情况来了,留言说:
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree >might get corrupted.
嵌套推送动画可能会导致导航栏损坏
在意外状态下完成导航转换。导航栏子视图树 > 可能会损坏。
My finding to this issue was that I was pushing 2 view controllers one after the other in quick succession and both were animated.
我对这个问题的发现是,我快速连续地一个接一个地推送 2 个视图控制器,并且两个视图控制器都是动画的。
In your case it seems that you might be popping multiple view controllers with animation one after the other.
在您的情况下,您似乎可能会一个接一个地弹出多个带有动画的视图控制器。
Hence, while one view is undergoing animation you should not start animation on another view.
因此,当一个视图正在播放动画时,您不应该在另一个视图上开始动画。
I also found that if I disabled animation on one view, the error message disappeared.
我还发现,如果我在一个视图上禁用动画,错误消息就会消失。
In my case it was a problem with the flow logic as I did not intend to push 2 view controllers one after the other. One was being pushed within the switch case logic and another after its end.
就我而言,这是流逻辑的问题,因为我不打算一个接一个地推送 2 个视图控制器。一个是在 switch case 逻辑中被推送,另一个是在它结束之后。
Hope this helps someone.
希望这可以帮助某人。
回答by Grady Player
You can get this anytime that you try to pop before viewDidAppear
. If you set a flag, then just check that flag in viewDidAppear
, you wont have a problem.
您可以在之前尝试弹出的任何时间获得此信息viewDidAppear
。如果您设置了一个标志,那么只需在 中检查该标志viewDidAppear
,您就不会遇到问题。
回答by Andrew
I have created a drop-in replacement for UINavigationController that will queue animations for you and avoid this problem entirely.
我为 UINavigationController 创建了一个替代品,它将为您排队动画并完全避免这个问题。
Grab it from BufferedNavigationController
回答by mbm29414
I had this problem, too, and here's what was causing mine:
我也有这个问题,这就是我的原因:
- In RootViewController, I am using several UISegmentedControl objects to determine which of many views to load next.
- In that (sub/2nd) view, I was popping (by using the "Back" button) back to RootViewController.
- In RootViewController, I was handling viewWillAppear to "reset" each of my UISegmentedControl objects to a selectedSegmentIndex of -1 (meaning no segment looks "pressed").
- That "reset" triggered each of my UISegmentedControl objects to fire their associated (and separate) IBActions.
- Since I wasn't handling for a "selection" of -1, I had multiple methods firing at the same time, all trying to push a different view.
- 在 RootViewController 中,我使用了几个 UISegmentedControl 对象来确定接下来要加载的视图中的哪一个。
- 在那个(sub/2nd)视图中,我弹出(通过使用“返回”按钮)回到 RootViewController。
- 在 RootViewController 中,我正在处理 viewWillAppear 以将我的每个 UISegmentedControl 对象“重置”为 -1 的 selectedSegmentIndex(意味着没有段看起来“按下”)。
- 该“重置”触发了我的每个 UISegmentedControl 对象以触发它们关联的(和单独的)IBAction。
- 由于我没有处理 -1 的“选择”,我同时触发了多个方法,所有方法都试图推送不同的视图。
My fix? I tightened up my if...then statements and bailed on executing any code in my UISegmentedControl IBActions when selectedSegmentIndex == -1.
我的修复?当 selectedSegmentIndex == -1 时,我收紧了 if...then 语句并放弃了在我的 UISegmentedControl IBActions 中执行任何代码。
I'm still not sure why I got "pop" animation errors and not "push" errors, but at least figured out my error and got it fixed!
我仍然不确定为什么会出现“pop”动画错误而不是“push”错误,但至少找出了我的错误并修复了它!
Hope this helps someone else!
希望这对其他人有帮助!
回答by MilGra
yeah, unfortunately apple did not synchronize UINavigationController's animations. Andrew's solution is excellent, but if you don't want to cover its whole functionality, there is a simpler solution, override these two methods :
是的,不幸的是,苹果没有同步 UINavigationController 的动画。Andrew 的解决方案非常好,但如果您不想涵盖其全部功能,则有一个更简单的解决方案,覆盖这两个方法:
// 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 ];
}
and create an NSMutableArray instance variable called waitingList, and you are done.
并创建一个名为 waitingList 的 NSMutableArray 实例变量,您就完成了。
回答by Juan Munhoes Junior
This problem happen with me when i use storyboards. I've made a mistake: I have a UIButton with an action to performSegueWithIdentifier. So i link the push segue with Button with the other ViewController so occur this problem.
当我使用故事板时,这个问题发生在我身上。我犯了一个错误:我有一个带有执行SegueWithIdentifier 操作的UIButton。所以我将带有 Button 的 push segue 与另一个 ViewController 链接起来,所以出现了这个问题。
To solve: Link the button action in UIButton and link the push segue between two ViewControllers.
解决方法:链接 UIButton 中的按钮动作,链接两个 ViewController 之间的 push segue。
回答by MarkWPiper
Combining MilGra and Andrew's answers gave me something that works reliably and is a simpler drop-in UINavigationController replacement.
结合 MilGra 和 Andrew 的答案给了我一些可靠工作的东西,并且是一个更简单的 UINavigationController 替代品。
This improves on MilGra's answer to make it work with pushes and pops, but is simpler than Andrew's BufferedNavigationController. (Using BufferedNavigationController I was occasionally getting transitions that would never complete and would only show a black screen.)
这改进了 MilGra 的答案,使其适用于推送和弹出,但比 Andrew 的 BufferedNavigationController 更简单。(使用 BufferedNavigationController 我偶尔会得到永远不会完成并且只会显示黑屏的转换。)
This whole thing seems not to be necessary on iOS8, but was still needed for me on iOS7.
这整个事情在 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