When working with a storyboard and segues, the usual method of performing a segue can be a bit cumbersome.
To deal with this, we’ve created a tiny helper called SegueManager that allows you to pass a closure to a performSegue
call.
Current situation
Say you have a simple storyboard containing two view controllers: a master and a detail controller, with a segue between them:
Usually at the point where you’re performing the segue, the information that needs to be passed to the destination segue is also available. However we can’t directly pass it to performSegueWithIdentifier
, but instead need to store it.
This is the code needed to store a string for later, and then perform the segue:
private var textForDetail: String?
@IBAction func openDetailAction(sender: UIButton) {
// Save text for later
textForDetail = "This is the detail screen!"
// Kick off segue
self.performSegueWithIdentifier("showDetail", sender: self)
}
The thing we want to pass to the detail view controller can be as simple as a single string, like it is here. But it can also be a complete view model, specific to the detail view controller.
This is the code needed to pass the stored string along to the destination view controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Segue is underway, update destination ViewController with value set earlier
if let vc = segue.destinationViewController as? DetailViewController {
vc.displayText = textForDetail;
}
}
Note that if you have want to add a second segue, to a different view controller, you need to add code in three different places;
- You need an extra
private var
for the view model of the second controller. - You need to add an extra
if let
check to theprepareForSegue
code where the private var is passed to the destination view controller. - At the place where you want to perform the segue, you have to also store the second view model in the private var.
Using SegueManager
With SegueManager
you can immediatly pass a closure that sets the view model. This nicely scales when using multiple segues.
You first have to create a SegueManager in the master view controller:
var segueManager: SegueManager!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// Create a segue manager based on the current view controller
segueManager = SegueManager(viewController: self)
}
Also, you still need to override prepareForSegue
, but it only needs one line of code that never needs to be changed:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
self.segueManager.prepareForSegue(segue);
}
And finally, when you want to perform a segue, you can call performSegue
on the SegueManager
:
segueManager.performSegue("showDetail") { segue in
let vc = segue.destinationViewController as DetailViewController
vc.displayText = "This is the detail screen!"
}
And that’s it! Now, when you want to add a second segue, you only need to add a second call to performSegue
, no other code needs to be changed.
Conclusion
Since the SegueManager is so little code, it’s available as a single gist that you can simply copy-and-paste into your project.
I’m curious, currently CocoaPods isn’t available for Swift, but once it is, would you like a tiny library like this to be available as a pod? Or would you be happy with just the gist as it is now?
2015-03-20: Now that CocoaPods has support for Swift, I’ve turned SegueManager into a cocoapod. OS X support has also been added.