Thursday, March 17, 2016

Segue Unwind to One of Two View Controllers (Swift 2.1)

Situation: I have a table view and a collection view. Both can go to the same view controller for editing an item. Now, how to get back to the correct starting view?

Resources I used:
Technical Note TN2298: Using Unwind Segues
Specifying the Destination of an Unwind Segue Programmatically
View Controller Programming Guide for iPhoneOS: UsingSegues

How I did it:
- Add an instance variable to both the table and collection view controllers. We'll use this to tell whether the containing controller started the segue. Default it to false, of course.
var startedEditorSegue = false

- Override the prepareForSegue function for both view controllers. Here, we'll set the startedEditorSegue variable to true, since we're starting the segue from the specified controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let segueId = segue.identifier else {
return
}
switch segueId {
case "tableViewSegueToEditor":
  // this controller is starting a segue to the editor, so unwind needs to return here
startedEditorSegue = true
default:
print("not editor segue")
}
}

Note: I don't have any untitled segues that should be coming through, so I used a guard statement. If you have untitled segues, you may want to use conditional unwrapping (if let segueId = segue.identifier...) or something else instead.


- Override each of the controller's canPerformUnwindSegueAction functions. If the controller started the segue, it will return true due to prepareForSegue code above. If not, the controller will return false.
override func canPerformUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject) -> Bool {
 // if we started the segue, then we can handle it; otherwise, pass
return startedEditorSegue
}
Note: if you need to do multiple unwind actions, you can check which one is occurring via the action parameter. In this case, the parameter will contain my custom selector: unwindFromEditor:


- Create a custom unwind function with the same name in both the table and collection view controllers. Here, we'll reset the startedEditorSegue to false, so it'll be ready for the next round.
@IBAction func unwindFromEditor(segue: UIStoryboardSegue) {

 // the editor's unwind came here; all we need do is revert the indicator
 // to false, so it's valid for the next unwind action
startedEditorSegue = false
}
Note:
* This action doesn't get "connected" to anything, but must be an @IBAction anyway.
* The name of the function can be anything you want.
* The function must have one parameter of type UIStoryboardSegue.


- In the storyboard, CTRL-drag from the editor view controller's button to initiate the segue to the same view controller's exit icon. You'll get a menu with your custom-named unwind action.



Select the action - and you're done!

Now, when the appropriate button is pressed, the unwind segue will traverse your view hierarchy. It'll ask each view whether it can respond to the unwind. Due to the canPerformUnwindSegue function in conjunction with the startedEditorSegue variable, the table and collection view will respond appropriately, and the process will return to the right place.

On a side note: you can give the segue an identifier: select the segue in the Storyboard's document outline, and open its Attributes Inspector.

Happy coding!



No comments:

Post a Comment