Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom Unwind Segue for iOS 8 and iOS 9

My question is, how do I get the following custom unwind segue to work on a device with a version prior to iOS 9 as well as on a device running iOS 9?

I have a Custom Segue showing a view controller, and then have a corresponding Custom Unwind Segue. This code has worked fine in iOS 8, and is implemented by creating subclasses of UIStoryboardSegue and implementing the perform method. Then I override the following method in my custom Navigation Controller:

- (UIStoryboardSegue *) segueForUnwindingToViewController:    (UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
    UIStoryboardSegue *segue;
    if([fromViewController isKindOfClass:[MyViewController class]]){
        segue = [[CustomSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; //Custom Unwind Segue
    }
    else{
        UIStoryboardSegue *unwindSegue = [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; //Normal Unwind Segue
        segue = unwindSegue;
    }
    return segue;
}

In iOS 9, segueForUnwindingToViewController is deprecated. It still works for the MyViewController CustomSegue; however, the default unwind segue no longer works for any other unwind segue. Although calling the method on super returns an unwind segue, the segue never occurs, the view controller is never popped, and the user can never go back to the previous screen. So just to be clear, if I use a regular show segue, the corresponding unwind segue calls the deprecated method, which calls the method on super, and does not work.

I watched the WWDC talk on storyboards, and I was able to fix this issue in iOS 9 by a) no longer overriding this method in my custom Navigation Controller, and b) going into the storyboard, clicking on the custom segue, and entering in CustomSegue as the Segue Class. Unfortunately, since I am targeting iOS 7, I get the warning "Only Custom segues support class names prior to iOS 9", and the custom unwind segue now does not work for iOS 7 or iOS 8!

like image 470
Josh Gafni Avatar asked Sep 22 '15 03:09

Josh Gafni


People also ask

What is unwind segue IOS?

Unlike the segues that you use to present view controllers, an unwind segue promises the dismissal of the current view controller without promising a specific target for the resulting transition. Instead, UIKit determines the target of an unwind segue programmatically at runtime.

How do you perform unwind segue programmatically?

To trigger an unwind segue programmatically (or any other segue), we need to give it an identifier in the storyboard. There is no arrow in a storyboard for unwind segues. To select one, you have to find it in the document outline on the left side of Interface Builder.

What is storyboard segue?

Segues are visual connectors between view controllers in your storyboards, shown as lines between the two controllers. They allow you to present one view controller from another, optionally using adaptive presentation so iPads behave one way while iPhones behave another.


1 Answers

After a lot of trial and error, I found a workaround. I noticed that when you override segueForUnwindingToViewController, unwindForSegue:towardsViewController is no longer called, which is the problem. FYI, Apple's note in UIViewController for segueForUnwindingToViewController says:

Deprecated. Returns a segue that will unwind from the source to destination view controller via the unwindForSegue:towardViewController: method. When performing an unwind segue defined in a storyboard, if any view controller along the unwind path has overridden this method and returns non-nil, the runtime will use that segue object instead of constructing an instance of the class specified in Interface Builder.

The portion of the statement in bold does not seem to be implemented, i.e. if you override this method but return nil, unwindForSegue:towardViewController is still not called and the segue does not occur.

In order to get around this problem, I was able to edit the segueForUnwindingToViewController in my custom Navigation Controller:

- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
    UIStoryboardSegue *segue;
    if([fromViewController isKindOfClass:[MyViewController class]]){
        segue = [[CustomSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; //Custom Unwind Segue
    }
    else{
        if([[UIDevice currentDevice].systemVersion floatValue] < 9.0){
            return [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; //Normal Unwind Segue
        }
        else{
            [super unwindForSegue:segue towardsViewController:toViewController];
            return nil;
        }
    }
    return segue;
}

UPDATE: Calling [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; seems to still work for modal unwind segues. The issue I described seems to happen for show segues. Consequently, if your device runs on a version < 9.0 or if the segue is modal, you should still call the old method. If you call [super unwindForSegue:segue towardsViewController:toViewController]; when the segue is modal, the segue will not work/occur.

like image 132
Josh Gafni Avatar answered Sep 28 '22 09:09

Josh Gafni