Search code examples
iosiphoneobjective-cuistoryboardsegue

Custom UIStoryboardSegue using segueWithIdentifier:source:destination:performHandler:


I am trying to use a custom UIStoryboardSegue to implement a transition between two view controllers. I can do this by subclassing UIStoryboardSegue, and then setting this class in IB. However, I was looking at the docs which say:

If your segue does not need to store additional information or provide anything other than a perform method, consider using the segueWithIdentifier:source:destination:performHandler: method instead.

Implying that you don't need to create the custom subclass, just use the custom performHandler.

I am confused as to where this code should go, and how I go about using it. Do I create the segue as normal in IB and then override that before it is fired (maybe in shouldPerformSegue: or similar). Elsewhere in apple's documentation it says:

Your app never creates segue objects directly; they are always created on your behalf by iOS when a segue is triggered

So I don't quite understand why they are then saying to instantiate a segue using a class creator method.


Solution

  • The point of segueWithIdentifier:source:destination:performHandler:

    • Provide an alternative to UIViewController performSegueWithIdentifier:sender in cases where you also want to create a custom transition, without creating a segue subclass.
    • Vend a segue that can be used as the return for segueForUnwindingToViewController:fromViewController:identifier

    As noted above, this approach is only viable for segues which you would call manually -- i.e. not for segues that would otherwise be triggered via IB triggers.

    So, for example, if you have a segue that needs to be triggered after a certain timeout period (such as a custom lock-screen), you could use segueWithIdentifier:source:destination:performHandler: to handle the custom transition.

    -(void)appTimeoutLockScreen
    {
        UIStoryboardSegue *segue = 
                    [UIStoryboardSegue segueWithIdentifier:@"LockScreenSegue" 
                                                    source:sourceVC 
                                               destination:destinationVC 
                                            performHandler:^{
                         // transition code that would 
                         // normally go in the perform method
                    }];
        // Dev is responsible for calling prepareForSegue and perform.
        // Note, the order of calls for an IB triggered segue as well as
        // a performSegueWithIdentifier segue is perform first, then
        // prepareForSegue:sender. Manual segues need to inverse the call
        // in order to ensure VC setup is finished before transition.
        [self prepareForSegue:segue sender:self];
        [segue perform];
    }
    

    Another practical use for the method is unwinding segues. Using a similar scenario to the previous example, we could use it to return a segue to transition from a lock screen back to the previous viewController:

    -(UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController*)toVC 
                                         fromViewController:(UIViewController *)fmVC
                                                 identifier:(NSString *)identifier
    {
        UIStoryboardSegue *segue = 
                [UIStoryboardSegue segueWithIdentifier:@"FromLockScreenSegue" 
                                                source:fmVC
                                           destination:toVC 
                                        performHandler:^{
                    // transition code
                }];
    
        return segue;
    }