Member-only story
Functional Dependency Injection in Swift
An alternative to Protocol-Oriented-Programming.

Almost all of us have created service-based protocols in order to facilitate unit testing in our applications. And we’ve also done them to enable previews when developing in SwiftUI.
The pattern is straightforward. Create a protocol describing what you want done. Then create a class or struct that implements that protocol. Next, implement some method for injecting an instance of that protocol into the class or service or view that depends on it.
That can be done using a classic dependency injection technique like constructor or property injection, or you can use a modern container-based system like Factory.
And then, finally, we implement a mock or stub or two that implements a dummy version of the protocol and inject that when we want to write a test or implement a preview.
Note: The examples below use Factory, but the same techniques can be used with pretty much any dependency injection pattern.
An Example
Enough talk, let’s define a very simple service that we can implement so we can look at some code and see what we’re talking about here.
The example I’ve chosen is a simple protocol for opening URLs. And in classic POP style, in order to make things easier we’re going to model our protocol on the existing openURL
function available on UIApplication
.
protocol URLOpening {
func openURL(_ url: URL) -> Bool
}
We then make sure UIApplication
conforms to our protocol.
extension UIApplication: URLOpening {}
With the protocol in place, we can create a factory to provide it.
extension Container {
static let urlOpening = Factory<URLOpening> {
UIApplication.shared
}
}
Since UIApplication
conforms to our protocol, we’ll just grab the shared instance whenever our dependency is needed.
And now, finally, we can make use of our freshly minted service. Here’s our view model.
class MyViewModel {
@Injected(urlOpening) var urlOpener
func open(site: String) {
_ =…