The initializer-based dependency injection provides many benefits. How could it be applied to the view controllers?
We often see code like this:
Which is an invitation to make a mistake.
The normal program flow is buried three levels deep. Yes, both conditions can be covered by a single if statement, but it doesn’t make code much more readable.
The identifier comparison is fragile. If the view controller identifier in the storyboard changes, the required photo will (silently) not be injected into the view controller. It is easy to overlook if the view controller is rarely used, and to get an unexpected runtime behavior.
The PhotoViewController’s interface lies. The object can’t be used without a photo, but it allows us to create itself without one.
The photo in the PhotoViewController is an optional. It’s good when it is an implicitly unwrapped one (or asserted very early) and the program exits on the spot, allowing the problem to be found sooner. But what if this optional property is not implicitly unwrapped or asserted. Then it becomes either an unwrapping hell everywhere the photo is used or a silent ignoring of nil, which is even worse.
So the property-based dependency injection is not a good idea. Let’s see how the program becomes more stable and predictable if the dependency is injected in the initializer.
Notice how the view controller now protects its internals and clearly states its dependencies.
We don’t care and don’t want to know how exactly it is created, from XIB or programmatically. No fragile identifiers or XIB names have to be specified externally.
The view controller can’t be created by mistake without a photo. No checks for nil required. No optional unwrappings or silent optional chainings inside.
If we want to show a “no photo” error, it can be done at some point earlier, at a place that knows that the photo couldn’t be retrieved. If it makes sense for the view controller to show an empty placeholder, the Null Object Pattern can be used. Either way, the view controller is kept free from dealing with the nil photo case.
Does this mean that storyboards should not be used? Exactly. Storyboards have their advantages and disadvantages, but this is perhaps the most compelling reason not to use them.
Framework developers pursue their goals. Once in a while, in the process of doing that, frameworks get features that may contradict with good programming practices. And sometimes, like in UIKit’s case, we absolutely have to use these frameworks. Luckily we often still have a choice. Our view controllers can become more stable and readable by using the initializer-based dependency injection and avoiding storyboards.