« MAIKit: A Framework for Sharing Code Between iOS and OS X | Main | Carbon and Cocoa as a Metaphor for Objective-C and Swift »

Avoiding Stringly-Typed Code in Storyboard View Controllers

At WWDC, Apple heavily promoted storyboards for both iOS and Mac development. Although storyboards aren't a good fit for every project, Apple is investing a lot of effort in improving storyboards, so it's becoming increasingly important for iOS and Mac developers to know how to use them. Segues are a fundamental building block of Storyboards, but the APIs provided to work with segues are some of the most stringly typed constructs in Cocoa and CocoaTouch. However, with a little reflection, we can create a better interface.

When using storyboards, it's not possible to connect IBOutlets between view controllers. When a view controller needs to store a reference to another view controller, it's common practice to override -prepareForSegue:sender:, and store the segue's -destinationViewController. Since this one method is called for every segue, and since the segues can only be differentiated by their identifiers, this leads to unwieldy if-else statements.

Since most view controllers only contain a few segues, I've always just gritted my teeth and followed this pattern when working with storyboards. But OS X storyboards will contain many more segues, and this pattern obviously does not scale well.

To solve this problem, we can override -prepareForSegue:sender: to call methods based on the segue's identifier. The following code does two things. First, if the view controller contains a property named segueTarget_<segue identifier>, it assigns the segue's -destinationViewController to that property. Second, if the view controller contains a method named -prepareForSegue:<segue identifier>sender:, it calls that method.

This behavior is inherited by both Objective-C and Swift subclasses of this view controller.

Of course, this is not a perfect solution. Like the stringly-typed version, this is brittle: It will break if you rename your segue without renaming the associated properties and methods. It would be much better if the segues themselves had targets and actions which could be set independent of their identifier.

I have created a Github repository with a view controller that implements this technique, as well as a similar technique for -shouldPerformSegueWithIdentifier:sender:. It's MIT-licensed, so please feel free to use it in your own code.

PrintView Printer Friendly Version

EmailEmail Article to Friend