UINavigationController's setViewControllers:animated: & canceled transition

Originator:thomas
Number:rdar://14794181 Date Originated:21-Aug-2013 12:22 PM
Status:Open Resolved:
Product:iOS SDK Product Version:iOS 7 DP 5(-6)
Classification:Serious bug Reproducible:YES
 
Summary:
When a interactive transition that was initiated by updating the view controller stack using UINavigationController's setViewControllers:animated: is cancelled, the view controller stack is not restored to the state before the setViewControllers:animated:.

Steps to Reproduce:
1. Present a nav controller with a root controller
2. Use setViewControllers:animated: to replace the top view controller with animated set to YES
3. Have the nav controller delegate return a animation controller and interaction controller (i.e. the transition is interactive)
4. Make the interaction controller cancel the transition

Expected Results:
The view controller stack (navigationController.viewControllers) is restored to how it was before the setViewControllers:animated: call, with the original root controller as the top view controller.

Actual Results:
The view controller stack now has both the original root view controller and the view controller that we set as its replacement. The stack height increased by 1.

Regression: N/A

Notes:
A workaround is to remove the second view controller when the transition cancels. I solved it by using the second view controller transitionCoordinator's notifyWhenInteractionEndsUsingBlock:. See for example the implementation of a method that replaces the top view controller:

`- (void) replaceTopViewController: (UIViewController *) viewController animated: (BOOL) animated
{
    // setViewControllers:animated:YES is currently buggy in iOS 7 beta. See e.g. https://devforums.apple.com/message/861601
    
    NSMutableArray *viewControllers = [NSMutableArray arrayWithArray: self.viewControllers];

    UIViewController *originalTopViewController = [viewControllers lastObject];
    
    [viewControllers replaceObjectAtIndex:viewControllers.count-1 withObject:viewController];
    [self setViewControllers:viewControllers animated:animated];
    
    [viewController.transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context) {
        if ([context isCancelled]) { // when the transition is cancelled, the to vc is unfortunately not removed by the navigation controller
            [self popViewControllerAnimated: NO];
            [self pushViewController:originalTopViewController animated:NO];
        }
    }];
}`

I would expect that the last lines (starting with [viewController.transitionCoordinator...) would not be necessary.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!