66

I have an app, that works fine under iOS 7, but when built for iOS 8 the unwind segues are not working.

I created a new project and added a modal (navigationcontroller with tableviewcontroller)and tried to use an unwind modal. Unfortunately it doesn't work either. The methods that are being unwind to, are in the desination view controller. The unwind segue is created through the storyboard (a Navigationbar button in the tableviewcontroller) When I tap the button, nothing happens. There is no log output and the modal does not disappear. It also only seems to affect modal segues. push/popover are unwound normally.

Has anyone had a similar problem and has an Idea how I could solve it?

viirus
  • 1,037
  • 1
  • 11
  • 21
  • 1
    I ran into this in a couple of places too - I'd been hoping it would be fixed by the time it gets to general release, but time is almost up! – bdalziel Sep 12 '14 at 17:59
  • 1
    You should update your accepted answer to @Stewart Hou's one as it is the only one that specifically addresses your issue. It will also help others experiencing the same problem find the right answer. – Rog Sep 18 '14 at 01:25

10 Answers10

60

Apple has FIXED this bug in iOS 8.1

Temporary solutions for iOS 8.0

The unwind segue will not work only in next situation:

View structure: UITabBarController -> UINagivationController -> UIViewController1 -> UIViewController2

Normally (in iOS 7, 8.1), When unwind from UIViewController2 to UIViewController1, it will call viewControllerForUnwindSegueAction in UIViewController1.

However in iOS 8.0 and 8.0.x, it will call viewControllerForUnwindSegueAction in UITabBarController instead of UIViewController1, that is why unwind segue no longer working.

Solution: override viewControllerForUnwindSegueAction in UITabBarController by create a custom UITabBarController and use the custom one.

For Swift

CustomTabBarController.swift

import UIKit

class CustomTabBarController: UITabBarController {

    override func viewControllerForUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject?) -> UIViewController? {
        var resultVC = self.selectedViewController?.viewControllerForUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender)
        return resultVC
    }

}

For old school Objective-C

CustomTabBarController.h

#import <UIKit/UIKit.h>

@interface CustomTabBarController : UITabBarController

@end

CustomTabBarController.m

#import "CustomTabBarController.h"

@interface CustomTabBarController ()

@end

@implementation CustomTabBarController

    -(UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
    {
        return [self.selectedViewController viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
    }

@end

==============================================================================

DO NOT USE ANY SOLUTIONS BELOW THIS POINT (they are out of date and just for reference)

Latest update on Sep 23

My new solution is pushing to a view that embedded in a navigation controller, and config that navigation controller to hide bottom bar on push(a tick box in IB). Then you will have a view looks like a modal view, the only different is the animate of pushing and popping. You can custom if you want

Updated: The solution below actually present the modal view under the tab bar, which will cause further view layout problems.

Change the segue type to Present As Popover will work only on iOS8 for iPhones, on iOS7 your app will crash.

Same here, to fix this, I set segue's presentation to current context(my app is for iphone only).

Default and full screen will not work.

enter image description here

Stewart Hou
  • 769
  • 6
  • 9
  • 1
    Have been banging my head against the wall on this for days. This is the solution that finally worked. Thanks! Can now build in XCode 6. – Alex McCarrier Sep 15 '14 at 20:22
  • All my modal segues on iPad were broken, this solved the issue for me as well. – Jesse Sep 18 '14 at 17:31
  • Setting Current Context as presentation type re-enabled the unwind segues for me. However there is still some unexpected behaviours. – DevC Sep 22 '14 at 08:40
  • Hi. This Current Context choice did work for the unwind but it has another side effect, the top of the modal I use is showing behind the navigation item! There is also another issue with Popover unwind. It seems calling another segue during this unwind operation is also broken. Any idea? – Eric Giguere Sep 22 '14 at 19:28
  • This works for the unwinding, however since I have tab bar controller that has navigation controller that presents another nav controller modally, using this approach somehow blocks tab bar controller's tabs. None of them are active once I dismiss modally presented VC. – Eimantas Sep 23 '14 at 11:23
  • 2
    Hello all. My latest and greatest fix: go back to the old delegate method! I use the segue to open a popover or a modal view, and use the standard delegate method to dismiss it. All back to normal! – Eric Giguere Sep 23 '14 at 12:40
  • Changing from Default to Current Context worked for me. It may be worth noting that it worked on iOS 8 as long as the presentation view controller was a "root" view controller, but if it was presented in a container my unwind stopped working. – barksten Sep 30 '14 at 17:14
  • well thats annoying :/ – anders Oct 29 '14 at 21:24
  • Thank you very much for update now unwind segue works perfectly in my iOS 8.0.0 – Arpit B Parekh Jun 15 '15 at 14:47
  • 1
    Is it possible that the 8.0 bug has returned in iOS 9? My unwind segue (with a tabbarcontroller) works fine on iOS 8.1, but stopped working on iOS 9... – cdf1982 Sep 24 '15 at 05:48
9

[UPDATE: Bug fixed on iOS 8.1 beta but you'll need it for 8.0 and 8.0.2 support]

The only way I could make my unwind segue work was by mixing Aditya's and viirus' answers.

My setup going in: [View Controller 1] > custom modal segue > [Navigation Controller] > root > [View Controller 2]

Unwind: [View Controller 2] > custom unwind segue > [View Controller 1]

Fix: Subclass the [Navigation Controller], add a property called sourceViewController and pass "self" to that property when prepare for segue is called when going from [View Controller 1] to [Navigation Controller]

In the [Navigation Controller] subclass .m override/add this two methods:

- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
{

    if ([self.sourceViewController canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender]) {
    return self.sourceViewController;
    }
    return [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];   
}

Then I override this in that [Navigation Controller] subclass only because I have a custom unwind segue:

- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
   return [fromViewController segueForUnwindingToViewController:toViewController
                                          fromViewController:fromViewController
                                                  identifier:identifier];
}
Raul Rea
  • 136
  • 4
  • The only solution that worked for me, thanks. In my case i was using a default unwind segue with similar setup. – alexandresoli Sep 17 '14 at 21:55
  • This is now causing the unwind function to be called on iOS 8, however, it doesn't automatically dismiss the modal VC when on iOS 7 it does. If I programmatically dismiss it then on iOS 7 I get a message logged: warning attempt to dismiss from view controller while a presentation or dismiss is in progress! How are you working around that? I don't want to have to detect the OS and if iOS 8 then manually dismiss. – Jordan H Sep 25 '14 at 21:25
6

This is a problem with iOS 8.0, 8.0.1, and 8.0.2. It was resolved in 8.1; unwind segues are calling the appropriate method now.

Note that on iOS 8, modally presented view controllers may not be automatically dismissed when performing an unwind segue, unlike iOS 7. To ensure it's always dismissed, you may detect if it's being dismissed and if not then manually dismiss it. These inconsistencies are resolved in iOS 9.0.

With iOS 8.4 running on iPhone, all of the modally presented segues with all presentation styles do dismiss upon unwind, except Over Full Screen and Over Current Context. That's also the case for iPad, with the addition of Form Sheet and Page Sheet also not auto-dismissing. With iOS 9, all presentation styles auto dismiss on both iPhone and iPad.

Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • Are you sure that __not dismissing__ is intended and not dependent on this bug? – DeFrenZ Oct 03 '14 at 17:14
  • 1
    I'm not positive if that's intended or a different bug @DavideDeFranceschi, I just stated the behavior I see and how to make it work like it does on iOS 7. – Jordan H Oct 03 '14 at 20:45
  • That is great news that this is fixed in iOS 8.1! – Richard Venable Oct 07 '14 at 16:08
  • 2
    In fact, unwind segues work fine when presenting a view controller modally with presentation style "Current". But as soon as you choose another presentation style, like "Over Full Screen" for example, then the unwind segue does not dismiss the view controller automatically. You have to add dismissViewController:animated: in the body of the unwind segue. – Frederic Adda Aug 09 '15 at 14:41
4

Yep it kinda happen to me too, I think for your case you have to subclass the UINavigationController and override the following:

    - (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
    {

        for(UIViewController *vc in self.viewControllers){
            // Always use -canPerformUnwindSegueAction:fromViewController:withSender:
            // to determine if a view controller wants to handle an unwind action.
            if ([vc canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender])
                return vc;
                }


        return [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
    }
Aditya Wirayudha
  • 1,024
  • 12
  • 19
  • Thanks a lot! I managed to get the segues to work, by adding a sourceViewController variable to the Navigationcontroller and setting it in the prepareForSegue call when displaying the modal. :) – viirus Sep 08 '14 at 19:43
  • Using this function in the nav controller I was hoping to unwind to, I was able to see that the specific Container View Controller I was hoping to unwind to, wasn't being called. I think that's the change we're seeing in iOS 8 - child container view controllers aren't being included in the unwind hierarchy flow – bdalziel Sep 15 '14 at 17:09
3

Same problem here. Unwind method is not called. Only happens when

  • using modal segue
  • Presentation is anything but "current context"
  • NavigationController is not extended (using default from storyboard)

Also happens in IOS8 GM Seed, therefore I think we need to find a workaround. Sounds like a bug to me...

Extending UINavigationController and implementing viewControllerForUnwindSegueAction didn't help, as it is not fired. The only thing which gets fired is canPerformUnwindSegueAction() within the extended UINavigationController. Strange.

Bertl
  • 605
  • 5
  • 10
  • 1
    Are you sure that canPerformUnwindSegueAction returns YES? for me the viewControllerForUnwindSegueAction was always fired in the subclassed UINavigationController – viirus Sep 15 '14 at 09:58
3

Woah there! I'm still getting user reports of getting stuck on a modal view in iOS 8.1.1 (on an iPad 3).

I'm jettisoning all this unwind from a modal view stuff. Just a good old-fashioned...

[self dismissViewControllerAnimated:NO completion:nil];

...works fine on all those various iOS 8.x.x versions.

Paul Brady
  • 503
  • 4
  • 10
3

It seems that both iOS 7.1 and iOS 8.1/8.2 create unwind segue from navigation controller however unwind segue is registered on a child controller inside of navigation controller.

So manually creating an unwind segue from the controller where it's registered in storyboard solves the problem.

@implementation RootNavigationController

- (UIStoryboardSegue*)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
    return [toViewController segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier];
}

@end
pronebird
  • 12,068
  • 5
  • 54
  • 82
1

I encountered the same problem when unwinding to a source view controller from a destination view controller. The destination was presented through a "show" segue from the source. I was using iPhone simulator that shows iPhone 6, iOS8.3. XCode 6.3.2

The solution of subclassing NavigationViewController worked for me. Here is the swift code which is essentially swift translation of Raul's answer. I am puzzled that if Apple has fixed it in iOS8.1 per Raul, how am I getting hit by it in 8.3.

var sourceViewController: UIViewController?
override func viewControllerForUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject?) -> UIViewController? {
        if(self.sourceViewController! .canPerformUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender!)){
            return self.sourceViewController
        }
        return super.viewControllerForUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender)
    }
0

I just ran into this problem, and after some digging discovered that with modal segues (at least ones with the default and fullscreen presentation modes), you can't rely on the normal unwind mechanism, but rather you have to call the presented UIViewController's dismissViewControllerAnimated method.

-2

Steps to be followed:

  1. Link the unwind segue to the button in Storyboard.
  2. Create IBAction for the button and add the below code in it:

    [self dismissViewControllerAnimated:NO completion:nil];
    

This should work for all versions.

Rick
  • 3,240
  • 2
  • 29
  • 53
Sai Apps
  • 3
  • 1