views:

309

answers:

2

I have a UINavigationController onto which I push a 'loading screen' UIViewController whilst I asynchronously connect to a server. The push is implicitly animated with that sliding effect. If an error occurs whilst connecting, I pop the loading screen controller (again animated) and display an alert to the user.

All is good if I pop the view controller after the animation has completed, however if the animation has yet to complete odd things occur. Usually the loading screen view remains on screen even though it has been popped from the navigation controllers stack. I'm pretty sure the problem has to do with the animation being in progress. For example this contrived code snippet always leaves secondController's view on screen for me:

[navController pushViewController: secondController animated: YES];
[navController popToRootViewControllerAnimated: YES];
NSAssert([delegate.navigationController.viewControllers count] == 1, @"oops");

My current workaround is register a delegate with the navigation controller and implement the navigationController:didShowViewController:animated: method. I then only pop the loading screen controller when I know the first push animation has completed. However I would prefer to just end the animation early.

I have tried to call removeAllAnimations on all layers in the layer tree for all sub views of the navigation controller's view. Whilst this approach ended the animation early, it still often left the loading screen view still on display after it had been popped. So basically is there a correct way of ending an animation early, or should I just stick with my work around?

A: 

It's hard to know why you would want to pop to the root view controller immediately after pushing it, but when I've had to do this sort of thing, I let the view controller being pushed determine if it needs to pop or not. So in your secondController's -viewDidLoad, determine whether or not your condition for popping to the root view is true. If it is, then pop from there by calling

[[self navigationController] popViewControllerAnimated:YES];

Also, not that this will fix your problem, but you may want to consider pushing a "loading screen" with -presentModalViewController instead:

- (void)presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated

and it's pop equivalent:

- (void)dismissModalViewControllerAnimated:(BOOL)animated
Matt Long
Thanks for the suggested workaround Matt! The reason it may be potentially popped before completion is due to receiving a 'connection failure' callback almost immediately after attempting to connect (perhaps due to the device being in airplane mode, etc). I push the loading screen, connect and then wait for the outcome of the connect attempt. If I could end the animation immediately in this callback it would save maintaining a bit of extra state and simplify the code a little :)
Deon Botha
A: 

Completely untested, but have you tried removing all animations from the core animation layer of your view controllers' view?

[[[secondController view] layer] removeAllAnimations];
Nathan de Vries