Dependency Injection in Swift (Mini Cake solution)

I already talked about the subject of Dependency Inversion here and of course the way to implement Dependency Inversion is to use Dependency Injection.

First let’s go back to what is Dependency Injection. Dependency injection is used to inject real implementations into a class that uses abstract interfaces instead. So let’s say a Presenter Class uses of View Class. If you are using SOLID, then your Presenter Class will “see” the View Class thru an abstract interface (a contract) and thus the dependency to the View Class will be reversed as you can see in the Fig-1.

Fig-1 : Presenter-Interface-View

When this is done, you can “insert” whatever View in the Presenter as long as it respects the View Protocol contract.

To do the insertion, you will use Dependency Injection. There are 2 types of Dependency Injection :

  1. Dependency Injection at instanciation
  2. Dependency Injection by modification

The first one is generally the preferred one, because it’s cleaner and enables to hide the used variables behind the class thus reinforcing the Open/Close Principle. In the first one, the dependency is passed to the class when it is created. The second one requires you to create a setter that will then modify the class after it was created. This can be dangerous if not done properly.

One could say that the second one should never be used and you could develop an architecture that could avoid its use almost completely (if not completely) but it means that you have to break all circular dependencies which sometimes you can’t. What is a circular dependency ? let’s look at Fig-2.

Fig-2 : circular dependency

It is obvious that you cannot create both classes at the same time. So you will have to create one, then create the second one with the first created one and then sets the property of the first one with the second one.

How can you do that in Swift ? Well it’s quite easy and here’s an example :

//: Playground - noun: a place where people can play

import Foundation

protocol PresenterProtocol {
    func trigger()
}

protocol ViewProtocol: class {
    func display()
}

class View {
    var presenter: PresenterProtocol?
}
extension View: ViewProtocol {
    func display() {
        print("display")
    }
}

class Presenter {
    private weak var view: ViewProtocol?
    init(view: ViewProtocol) {
        self.view = view
    }
}
extension Presenter: PresenterProtocol {
    func trigger() {
        print("trigger")
    }
}

let view = View()
let presenter = Presenter(view: view)
view.presenter = presenter

In this code sample, Presenter Class and View Class have no dependency (they “see” each other thru interfaces) and the injection is done using both methods (notice the way you avoid retain cycle by using weak in Presenter Class for the private variable “view”). The last 2 lines do the injection of dependencies.
But now, what if you want to use all this inside your project. The first easy idea is to put those 3 last lines inside another class like this :

class Injector {
    func bind() -> View {
        let view = View()
        let presenter = Presenter(view: view)
        view.presenter = presenter
        return view
    }
}

Then your architecture becomes this :

Fig-3

One could say this is fine and enough for what you need to do and I could agree. On the other hand, what if this module (Module A) is used by another module (Module B) and you need to unit test this other module. First you are creating a strong dependency between the Module B and Module A and second, there’s no way for Module B to mock Module A and so your unit test are going to be painful. How to handle that : one solution is to use Dependency Injection Framework like Swinject or DIP. Those are very good frameworks but they come with a price :

  • they do all the wiring at runtime
  • they are using Strings to do the wiring and thus are not strongly typed
  • they require to load the framework before doing the wiring and thus increase the loading time

The alternative is to use protocol with protocol extension and thus implement a sort of Mini Cake Pattern. The Cake Pattern is a pattern to do dependency injection in Scala (at least I know it from Scala – here in french or here in English).

Let’s see how this work :

protocol Injector {
    func resolve() -> ViewProtocol
    func resolveInternal() -> ViewProtocol
    func resolve(view: ViewProtocol) -> PresenterProtocol
}

extension Injector {
    func resolve() -> ViewProtocol{
        let view = resolveInternal()
        let presenter = resolve(view: view)
        view.presenter = presenter
        return view
    }
    func resolveInternal() -> ViewProtocol {
        return View()
    }
    func resolve(view: ViewProtocol) -> PresenterProtocol {
        return Presenter(view: view)
    }
}

class InjectorImpl: Injector {}

The architecture dependency graph is now this :

Mini Cake Graph

The external Module now sees only interfaces (in our example : Injector, ViewProtocol and PresenterProtocol) and we can inject anything into it as long as it respects the Injector interface. (The default implementation made in the protocol extension will make it easy to mock without having to rewrite everything).
For example, let’s say I want to mock the View Class, I could do this :

class MockedView {
    var presenter: PresenterProtocol?
    var displayWasCalled = false
}
extension MockedView: ViewProtocol {
    func display() {
        displayWasCalled = true
    }
}
class InjectorWithMockView: Injector {
    func resolveInternal() -> ViewProtocol {
        return MockedView()
    }
}

And now you see that the InjectorWithMockView class implements correctly Injector interface (because we used protocol extension in Swift all the other default implementations are done and “func resolveInternal() -> ViewProtocol” is just returning the MockedView object that could then be used for tests using the displayWasCalled boolean for example). And voilà : you have Dependency Injection with the possibility to inject whatever you want. One could say that we will need an Injector to inject the Injector in the Module B and one is right but this will all depend where you need to push your Unit Tests and decoupling, because at the end the day one file will need to rule them all for sure but with correctly implemented Dependency Inversion you will handle your code coverage correctly and make your Unit Tests really easy. Just imagine that you could completely mock a module used to handle a webservice for example… thus making your tests not depending on any external server 🙂

Have a nice day. Best regards.

Fred.

Some references and other articles covering the same topic (some of them used as inspiration for sure) :

  • https://medium.com/makingtuenti/dependency-injection-in-swift-part-1-236fddad144a
  • https://medium.com/ios-os-x-development/dependency-injection-in-swift-a959c6eee0ab
  • https://github.com/orakaro/Pure-Swift-Dependency-Injection

2 thoughts on “Dependency Injection in Swift (Mini Cake solution)”

Leave a Reply

Your email address will not be published. Required fields are marked *