Swift Tip: Type-Safe Initialization using Storyboards (Part 1)
Love them or hate them, Storyboards are used in many iOS projects. In this week's Swift Tip, we look at a simple way to make them more robust.
When you present a new view controller using Storyboards, it's usually a multi-step process: first, the segue is triggered, and at a later step, you configure the segue. This makes it easy to miss configuration code.
For example, in the code below, we set the two properties that the PlayViewController
needs:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail",
let playVC = segue.destination as? PlayViewController {
playVC.context = self.managedObjectContext
playVC.recording = selectedRecording
}
}
It's easy to forget one of the above properties, because it's often not clear which properties are required, and because view controllers typically have many stored properties. What's more, when you're in the RootViewController
, you don't always have all the details of PlayViewController
to hand. Because of the multi-step initialization process, we can't put this in the initializer either (the PlayViewController
has already been constructed by the time we end up in prepare(for:sender:)
).
As an improvement, we can adopt the convention that each view controller has a configure
method which takes the necessary parameters:
func configure(context: NSManagedObjectContext, recording: Recording) {
self.context = context
self.recording = recording
}
Now, in prepare(for:sender:)
you can rely on autocomplete and the compiler to make sure you provide all the necessary parameters:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showDetail",
let playVC = segue.destination as? PlayViewController {
playVC.configure(context: self.managedObjectContext, recording: selectedRecording)
}
}
This approach is much more robust when refactoring; for example, we can add another required parameter to the configure method, and the compiler will indicate all the places we need to change. As long as we are disciplined about calling configure
rather than setting the properties manually, we're safe.
In Part 2, we show an alternative approach taken from our new book, App Architecture. In the MVVM-C implementation, we use Storyboards to lay out the view controllers, but provide static wrapper methods that construct the view controllers with the required parameters. Instead of segues, we move the logic into a coordinator class, and manually trigger presentation.
We demonstrate a similar refactoring in Swift Talk Episode 5.