I use custom transitions for modal segue, implemented using UIViewControllerAnimatedTransitioning delegate. All segues setup via Storyboard.
I have two nav controllers, both have single root VC setup. Let's call them 1st NVC
, 1st VC
, 2nd NVC
and 2nd VC
.
1st VC
adopts the UIViewControllerAnimatedTransitioning
protocol, implementation simply returns animator:
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
return [ModalTransitionAnimator new];
}
- (id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
return [ModalTransitionAnimator new];
}
When any segue happens from 1st VC
-> 2nd NVC
, 1st VC
catches the event in prepareForSegue:
and assigns transitioningDelegate
along with modalPresentationStyle because you cannot do that from IB:
UINavigationController* destination = (UINavigationController*)segue.destinationViewController;
destination.transitioningDelegate = self;
destination.modalPresentationStyle = UIModalPresentationCustom;
So everything seems fine, I get a very cool animation running, destination controller shows up, all viewWillAppear:
and viewDidAppear:
fire in the right order.
And so now on screen, I have 2nd NVC
with 2nd VC
inside.
I tap "Cancel" button in Navigation bar, unwind action triggers on 1st VC
, but no backward animation happening. I mean in fact 2nd VC
is still on screen.
So apparently nobody calls dismissViewControllerAnimated. I suppose Storyboard is confused and can't find the way back because 2nd NVC
was initially modally presented and then some other controller requests unwinding. How do you deal with that normally?
I followed the unwind chain and found that UIKit was not able to find the right unwind segue after state restoration. Before state restoration everything worked perfectly fine.
I fixed it manually and traversed my controllers hierarchy to return a controller that has unwind action defined:
- (UIViewController*)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
if([NSStringFromSelector(action) hasPrefix:@"unwindToInitialViewController"]) {
return [[((UINavigationController*)self.centerViewController) viewControllers] firstObject];
}
UIViewController* c = [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
DDLogInfo(@"%s = %@, c = %@", __PRETTY_FUNCTION__, NSStringFromSelector(action), c);
return c;
}