3 Comments

Specifying the Destination of an Unwind Segue Programmatically

I once wrote an iPad app to help people take self-guided tours through a museum. One of the interesting parts of this application was that many of the views were implemented by the same view controller. The functionality of each screen remained the same with slightly different assets in each view. This would be a problem if I needed to Unwind to certain screens in my application.

So far in this series, we’ve learned that for Unwind Segues to work, you need to specify your destination view controller by implementing an unwind handler in the destination view controller. If every screen is implemented by the same view controller, this makes it difficult to specify which view controller to unwind to. Alternatively, you may have some business logic that will determine the destination.

In this blog post, I’ll will show you how to programmatically determine the destination of an Unwind Segue.

Changes to the Example

I am going to modify the sample application that I’ve been using in this series so far. I still have three view controllers, with a “Next” button on each that goes from #1 to #3 in order.

Unwind example

For this post, I added a switch control on #1 and #2 that we will use to determine if the Unwind should stop at that view controller. I also created an Unwind Segue that goes from #3 back to the first view controller in the responder chain that has the switch turned on (#2 or #1).

1. Adding the Unwind Segue in Interface Builder

The first thing to do is add handler code to view controller #1 and #2. I will add the same handler function in each. (What you name the function does not matter as long as they are identical in both view controllers.) If you had each view implemented by the same view controller, you obviously only need to add the function once.

 @IBAction func prepareForUnwind(segue: UIStoryboardSegue) {

}

-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}

Adding the Unwind SegueThen add the Unwind Segue as you normally would in Interface Builder. Ctrl-drag from the “Unwind” button in view controller #3 to the “Exit” outlet, and you will see a modal popup with the name of our handler. Select it.

2. Specifying the Destination

Next, override a function in view controller #1 and #2 called canPerformUnwindSegueAction. The system will call this function to determine if a view controller should be the destination of the Unwind. Return YES if you want the Unwind Segue to stop here or NO to continue down the responder chain.

Let’s take a look at our implementation of this function using the switch we added in the UI to determine if we should stop at this view controller.

override func canPerformUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject) -> Bool {

if (self.respondsToSelector(action)) {

 return self.unwindHere.on;

 }

 return false;

}

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

 if ([self respondsToSelector:action]) {

 return self.unwindHere.isOn;

}

return NO;

}

The property self.unwindHere is the outlet to my switch control. I simply return the value of the switch in the function.

I also added an additional check to be sure the selector that’s passed in matched the Unwind handler prepareForUnwind that I have implemented in each view controller. When I run the app, I can dynamically determine if my Unwind Segue will go from #3 to #2 or from #3 to #1 depending on how I have set my switches.

That is all there is to it. If you want to read more, I suggest looking at Apple’s Technical Note TN2298 and scroll down to the section called “How an Unwind Segue Determines its Destination View Controller”.


This is the fourth part of my series on Unwind Segues: