IOS: unexpected behavior of popViewController

I searched the internet for a solution. I could not find anything. So: I use UINavigationController. I click on it with two UIViewControllers. In the second clicked ViewController, I execute this code:

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

The expected thing to happen is that the last clicked ViewController will disappear. In this application, I do this in several places, and it works great everywhere, as expected in this ViewController itself. It happens that only the back button is disconnected from the screen (animated), but everything else remains on the screen. On the Console output, two lines are printed after this line is executed:

2011-03-14 16: 32: 44,580 TheAppXY [18518: 207] nested pop animation may damage the navigation bar

2011-03-14 16: 32: 53.507 TheAppXY [18518: 207] Completion of the transition to an unexpected state. The navigation tree of the navigation in the navigation bar may be damaged.

Two error messages for which I could not find ANY information. I am using Xcode 4 and iOS SDK 4.3. Maybe someone can help me with this problem.

+49
ios xcode uinavigationcontroller
Mar 14 '11 at 15:51
source share
7 answers

I ran into a similar situation in my code, and the message said:

Nested push animations can damage the navigation bar

Completing the navigation transition in an unexpected state. The navigation tree's visibility tree> may be damaged.

My discovery of this problem was that I clicked on two view controllers several times one after another, and both were animated.

In your case, it seems that you can display multiple view controllers with animation several times.

Therefore, while one view goes through the animation, you should not run the animation on another view.

I also found that if I turned off the animation on one view, the error message disappeared.

In my case, it was a problem with the flow logic, because I was not going to press two view controllers one by one. One of them was inserted into the logic of the switch, and the other after its completion.

Hope this helps someone.

+50
May 19 '11 at 1:49 a.m.
source share

You can get this at any time that you are trying to execute before viewDidAppear . If you set a flag, then just check this flag in viewDidAppear , you will not have a problem.

+28
May 6 '11 at 21:01
source share

I created a replacement for the UINavigationController that will stop the animation for you and completely eliminate this problem.

Take it from the BufferedNavigationController

+12
Dec 20 '11 at 8:19
source share

I had this problem too, and here is what caused mine:

  • In the RootViewController, I use several UISegmentedControl objects to determine which of the many types to load next.
  • In this (sub / 2nd) view, I pressed (using the "Back" button) back to the RootViewController.
  • In RootViewController, I handled viewWillAppear to โ€œresetโ€ each of my UISegmentedControl objects for selectedSegmentIndex -1 (which means the segment does not look โ€œclickedโ€).
  • That "reset" caused each of my UISegmentedControl objects to run their associated (and individual) IBActions.
  • Since I did not process the โ€œselectionโ€ of -1, several methods worked at the same time, everyone tried to click on a different view.

My fix? I tightened my if ... then instructions and executed some code in the UISegmentedControl IBActions when selecting SegmentIndex == -1.

I'm still not sure why I got pop-animation errors, not push, but at least figured out my mistake and fixed it!

Hope this helps someone else!

+3
Jun 14 2018-11-11T00:
source share

Yes, unfortunately, the apple did not sync the UINavigationController animation. Andrew's solution is great, but if you don't want to cover all your functionality, there is a simpler solution, override these two methods:

 // 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 waitList and you are done.

0
Mar 01 2018-12-12T00:
source share

This problem occurs to me when I use storyboards. I made a mistake: I have a UIButton with an action to execute a SegueWithIdentifier. Therefore, I associate the push sega with Button with another ViewController, so this problem occurs.

To solve: Bind the button action in UIButton and connect the push seg between the two ViewControllers.

0
Aug 14 '13 at 16:00
source share

Combining the answers of Milgra and Andrew, I gave me something that works reliably and is a simpler replacement for the UINavigationController replacement.

This improves Milgra's response to make it work with shocks and buttocks, but easier than Andrew BufferedNavigationController. (Using the BufferedNavigationController, I sometimes got transitions that will never be completed and will only show a black screen.)

This whole thing doesn't seem to be needed on iOS8, but I still needed it on 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
Jun 20 '15 at 7:32
source share



All Articles