Dependency Injection in Swift

3 min readJan 17, 2021

Dependency injection is better understood with the help of an example. So let’s jump directly into it.

In this example, Object A depends on Object B and/or Object C. Therefore, Obj A creates instances of Obj B and/or Obj C inside one of its functions. It would look something like the following.

Dependency Directed Graph
class A {

let b = B()
b.call(withModel: Model) {result in ... }
}

This makes our code testing difficult because if an error occurs in class B, its indirect effect would be in class A. This disregards the principle of code isolation, i.e, code should be testable in isolation.

Thus, dependencies (obj B and/or obj C) are injected (into A) rather than being created. This is called dependency injection where the ready-to-use results from objects B and C are passed back to object A for use.

Dependency Injection Directed Graph

In terms of unit testing, this makes our testing easier as we can fake our obj B and obj C, to test obj A in isolation. Here we do not inject actual dependency in testing, but create the mocks of dependency and inject into A for unit testing class A.

Using Mocks in Dependency Injection for Unit Testing

Types of Dependency Injection

Dependencies can be injected in many ways. However, developers use the 3 most common ways of dependency injections. These are discussed as follows:

  1. Method Dependency Injection
  2. Initializer Dependency Injection
  3. Property Dependency Injection

Consider another example here to understand the above 3 kinds of dependency injection. Let’s say you want to call a web service from a function like below via a button click:

Object Instantiation (Incorrect way of using dependencies by creating them)

func callWebService(model: Model) {    let webService = WebService()    webService.call(withModel: Model) {result in        ...    }}

In the above method, the webService object (dependency) is created inside callWebService function of some random class that makes the code testing in isolation difficult.

Method Dependency Injection

The correct way would be to provide the webService (dependency) as a function argument (ready-to-use object) which would be termed as dependency injection since we are injecting the dependency in our object rather than creating it. This type of dependency injection is called Method Dependency Injection.

func callWebService(model: Model, webService: WebService) {    webService.call(withModel: Model) {result in        ...    }}

Initializer Dependency Injection

Another common way to achieve the above result is Initializer Dependency Injection as detailed below:

class WebServiceUtil: WebServiceUtilProtocol {    var webService: WebService    required init(webService: WebService) {        self.webService = webService    }
func callWebService(model: Model) { self.webService.call(withModel: Model) {result in ... } }}

Property Dependency Injection

Yet another way to achieve dependency injection.

let vm = ViewModel()vm.webService = WebService()

Hope that makes a difference to our knowledge.

Cheers!

--

--

Nishant Paul
Nishant Paul

Written by Nishant Paul

iOS Application Developer / Technology Enthusiast @Dream11

No responses yet