Safer Storyboards in Swift
A swifty approach to dependency injection.
Note: Medium does not display code snippets on the mobile app, please visit this article in a browser, or follow this alternate link for a better reading experience on mobile.
UIKit. Love it or hate it, there are many idiosyncrasies that can make working with Apple frameworks not so pleasant in Swift.
Storyboards are an interesting example of how the patterns of UIKit really clash with swift paradigms and I’ve been searching for ways to handle storyboard dependency injection that is safe and easy to use.
Plain storyboards lend themselves to a lot of type casting and *shudder* implicitly unwrapped optionals. Because the initialisation of the ViewControllers is out of your control, you lose the ability to require that your dependencies are set at instantiation time.
There are a few approaches floating around that somewhat mitigate these issues including Factories, Reflection, Completion Blocks and Plain Old Segues. These are all fine approaches, but I’ve been working on an approach that is a bit more swifty, simple, and takes advantage of protocols and generics.
Firstly, we need a way to encapsulate the configuration of our ViewControllers with a given set of dependencies. I’ve called this the ‘Scene’ protocol. It provides an identifier string and a function that takes a ViewController and configures it.
Note the use of an associatedtype here. This will allow us to ensure that the ViewController we configure is the type we want at compile time (and throw an error if this isn’t the case).
Because I like to be as lazy as possible, I’ve also provided this extension to Scene which gives a sensible default value for our identifier (in this case the class name of the ViewController).
So now all we need is a way to construct a ViewController from our Storyboard, and configure it using our Scene. We can add an extension to UIStoryboard to allow this, which makes our API nice and simple:
So how does this look in practice? Well first we need to create a Scene for out ViewController in our storyboard, and then create our ViewController from the storyboard using our scene:
By encapsulating the construction and dependency injection of our ViewControllers, we can be sure that our dependencies are correctly set up before we use them. As a bonus, the ViewController will automatically be casted to the correct type, and a nice error will be displayed if this cast fails (time to go and fix those storyboard identifiers 😜).
Note that this won’t work with segues out of the box, but I generally avoid them anyway (feel free to argue with me about this on twitter if you like 😊).
I’d love to hear feedback on this approach, and if anyone has experimented with other ways to work around the limitations of storyboards.