How To: Dependency Injection In Swift

Written by: Reinder de Vries, July 4 2017, in App Development

How To: Dependency Injection In Swift

Dependency Injection sounds scary… but it’s actually pretty simple. On top of that, understanding dependency injection will greatly improve your code quality and productivity as a Swift developer!

This is Wikipedia’s description of dependency injection:

Dependency injection is a technique whereby one object supplies the dependencies of another object. A dependency is an object that can be used, like a service. An injection is the passing of a dependency to a dependent object (a client) that would use it. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.

Perhaps you’ve heard about these development principles:

  • Don’t Repeat Yourself (DRY) Principle
  • Separation of Concerns and Single Responsibility Principle
  • Loose Coupling or Decoupling

All these principles have one thing in common: they make your code more maintainable by making it modular. Instead of creating one big pile of code, you create separate your code into modules that interact with each other.

How To: Dependency Injection In Swift

You’ve probably heard of “spaghetti code” before. It’s a chaotic codebase, that’s hard to maintain, and even harder to improve. You want to avoid spaghetti code at all costs, and dependency injection helps with that.

Ready? Let’s find out how!

  1. What Is A Dependency?
  2. Dependency Injection
  3. When To Use Dependency Injection
  4. Two Different Methods of Dependency Injection
  5. Further Reading

What Is A Dependency?

Let’s first start by finding out what dependency injection really is.

You’ll soon realize that the term “dependency injection” is, in fact, a perfect word for this development concept. You’re literally injecting a dependency with code.

But… what’s a dependency? OK, let’s look at this code example.

protocol Propulsion {
    func move()
}

class Vehicle
{
    let engine: Propulsion

    init() {
        engine = RaceCarEngine()
    }

    func forward() {
        engine.move()
    }
}

It’s Swift code and you see two things:

  • A protocol Propulsion
  • A class Vehicle

The protocol Propulsion defines one function: move(). When a class wants to conform to the protocol, it will need to implement that move() function.

The class has one property engine, of protocol type Propulsion. You can assign any type of object to engine as long as it conforms to the Propulsion protocol.

When an instance of Vehicle is initialized, an instance of RaceCarEngine is assigned to the property engine. Then, when the function forward() is called, the vehicle will call the move() function on the engine object.

Imagine the following scenario:

  • You have a special car: you can switch out its engine for anything you want: a jet engine, a rocket engine, a race car engine…
  • To make sure any engine actually works, you’ve defined a rule for engines for your car: they must be able to move

That’s what you see in the above code example. The protocol Propulsion defines the rules for the engine, and within the Vehicle functions the engine is initialized and used to call the move() function.

Here’s the actual car engine:

class RaceCarEngine: Propulsion {
    func move() {
        print("Vrrrooooommm!!")
    }
}

As you can see it implements the Propulsion protocol, and defines an implementation for the required move() function.

Here’s how you use them together:

var car = Vehicle()
car.forward()
// Output: Vrrrooooommm!!

You define a car variable of type Vehicle, and call the forward() function to move the car with the engine.

So what’s the dependency here?

The dependency is inside the init() function of Vehicle, because it references the RaceCarEngine class. Class Vehicle is tightly coupled with the RaceCarEngine class. You don’t want that!

Because you’ve directly referenced RaceCarEngine from Vehicle, the Vehicle class now depends on the RaceCarEngine to function.

Is there away to get around that?

Get 5 of my best practices

Get 5 of my best practices

Learn how to build better iOS apps

I’ll show you exactly how I built a dozen professional iOS apps,
write extensible Swift code, and turn coffee into code.
Wait, what? Yup – into Swift code.

Dependency Injection In Swift

Unfortunately, there’s no way to get around dependencies. Dependencies aren’t bad! Your app’s code is interconnected, because all its components need to work together.

What is bad about dependencies is that it’s easy to create tightly coupled modules, with dependencies all over the place. A typical sign of spaghetti code is non-modularity and no structure for dependencies.

OK, let’s get back to dependency injection. Here’s how you can use dependency injection to clean up the previous example:

class Vehicle
{
    let engine: Propulsion

    init(engine: Propulsion) {
        self.engine = engine
    }

    func forward() {
        engine.move()
    }
}

The difference is subtle. Instead of directly using the RaceCarEngine class, the Vehicle class now takes a Propulsion instance as an initializer parameter.

You can see that in the init() function. A parameter engine can be passed to the initializer function. Within the initializer, it’s assigned to the engine property.

Here’s how it then works together:

let raceCarEngine = RaceCarEngine()

var car = Vehicle(engine: raceCarEngine)
car.forward()
// Output: Vrrrooooommm!!

Instead of directly using the RaceCarEngine inside the Vehicle class, it’s now used outside the Vehicle class and injected as a parameter via the initializer.

This is dependency injection.

OK, now let’s look at another code sample:

class RocketEngine: Propulsion {
    func move() {
        print("3-2-1... LIFT OFF... PPPPSSSSCHHHHOOOOOOOOOMMMMMM!!!")
    }
}

Yup – you got that right, it’s a rocket engine! (And my ppssscchhoommm!! imagination of a rocket engine taking off…)

Without a whole lot of trouble you can switch out the race car engine in your car for a rocket engine…

let rocketEngine = RocketEngine()

var car = Vehicle(engine: rocketEngine)
car.forward()
// Output: 3-2-1... LIFT OFF... PPPPSSSSCHHHHOOOOOOOOOMMMMMM!!!

Don’t get this the wrong way: you could have switched out the engine without using dependency injection! You simply would have changed the Vehicle class to change the engine type, right?

Well, here’s three reasons why that might not have worked:

  1. You didn’t have access to the Vehicle class code, because someone else wrote it (or is still writing it…)
  2. The rocket engine class isn’t ready yet, so you’re forced to create a “fake” class for testing purposes, that is similar to the rocket engine class (this is called mocking)
  3. You want to test the rocket engine class, so you need to be able to switch it out for a diagnostics rocket engine that logs everything it does (this is called unit testing)

Let’s look at those reasons in the next section…

Build better iOS apps by mastering best practices and app architecture » Find out how

When To Use Dependency Injection

Dependency injection is useful in the following scenarios:

  1. You want to change the implementation of code you don’t have access to
  2. You want to “mock” certain behavior in your code
  3. You want to test your code

First of all, dependency injection is simply part of good code architecture and design. It increases the modularity of your code, it helps with separating concerns, and it makes your code easier to maintain.

1. Code You Don’t Have Access To

You’re working with code you don’t have access to, all the time! Think about the UIKit frameworks, or a Firebase library, or Alamofire. Even though you have, strictly speaking, “access” to the code – you can’t change it!

The Cocoa Touch SDK has a neat solution for that: delegation. Delegation is a programming design pattern that enables a class to hand-off some of its responsibilities to another class instance.

In many Cocoa Touch classes you can assign your own object to special delegate properties. The framework classes then call functions on your delegate objects. Since you have control over the delegate objects, you can change the behavior of framework classes without changing their code directly.

Similarly, when you’re working with another developer, you can use the same “hand off” principle:

  • The other developer is responsible for integrating with a REST API
  • You both agree that the REST API should implement a function getItems()
  • Until the REST API is ready, you create your own REST API stub that returns fake data
  • When the REST API is ready, you switch out the classes and inject the correct dependency in your own code

Moreover, when the time comes to replace the REST API with a new back-end, you only have to code the back-end implementation. If the new back-end exposes the same getItems() function, it should work perfectly fine. Yay, modularity!

2. Creating Mock Classes

With dependency injection you can easily switch out dependencies. In the previous example, the one with the car engine, you saw that you could change the engine implementation of the car.

Say that you were really building a rocket engine. You’ve got two types of engines:

  • The actual rocket engine
  • A diagnostics rocket engine

The diagnostics rocket engine sends logging data to an external service. When it starts up, it’ll send a I'm starting up message to the logging service. The rocket engine also does more calculations to generate diagnostics data, so it’s more resource intensive.

With dependency injection you can easily switch out the actual rocket engine, and the diagnostics engine without changing any core rocket code.

Also, when the rocket engine isn’t ready yet, you can create a “mock” engine. In practical iOS app development this happens for instance when you’re working with an external API. The API isn’t ready yet, so you create a mock API that just returns representative “fake” data. Based on the data you can build your app. When the real API is ready, you simply add in the new dependency and you’re done.

3. Dependency Injection and Unit Tests

Unit testing is a practice in software development to test the output of code, based on a given input, and comparing that output to a predefined value.

Compare it to a simple pocket calculator. You test whether the addition function works correctly by calculating 1 + 1. When the result is 2, you know it works, and when the result is something else, you know the function is broken.

Unit testing is typically labor intensive, so you want to automate as much as possible. It’s easier to test modular code that isn’t tightly coupled. With dependency injection you can quickly inject a testing class as a dependency without having to replace entire blocks of code.

You can test the dependency itself, i.e. if the rocket engine runs smoothly, or the code that uses the dependency, i.e. if the rocket moves based on input from the rocket engine.

Dependency injection makes your Swift code more modular, and easier to maintain Click To Tweet

Two Different Methods of Dependency Injection

You can use dependency injection in Swift in two ways:

  • With constructor injection, i.e. injecting the dependency via the class initializer
  • With setter injection, i.e. by injecting the dependency via a setter function

Both methods have distinct use cases:

  • It’s recommended to use constructor injection for a dependency that doesn’t change during the lifetime of the dependant object
  • When the dependency can change during the lifetime of the dependant object, or when it’s nil at initialization, it’s better to use setter injection

In the previous example you used constructor injection to provide the Vehicle class with the RocketEngine object:

var car = Vehicle(engine: rocketEngine)

The variable rocketEngine is provided as an argument for the Vehicle constructor method, thus constructor injection (in Swift, it’s called an initializer).

Setter injection isn’t much different. Instead of injecting the dependency as a constructor argument, you pass it as the argument to a setter function:

car.setEngine(rocketEngine)

In Swift you can also use the property, of course.

car.engine = rocketEngine

One of the beneficial side-effects of using constructor injection is that it becomes very clear when a particular class violates the Single responsibility principle.

The single responsibility principle states that, logically, every class should have one responsibility. Think “communicate with the REST webservice” or “retrieve/write data from the database”.

When a constructor takes a large number of dependencies as parameters, you should suspect it violates the single responsibility principle. After all, why would it need so many dependencies if it only has one thing to be responsible for?

Get 5 of my best practices

Get 5 of my best practices

Learn how to build better iOS apps

I’ll show you exactly how I built a dozen professional iOS apps,
write extensible Swift code, and turn coffee into code.
Wait, what? Yup – into Swift code.

Further Reading

Understanding dependency injection is a great step towards creating more modular, more maintainable and less error-prone code.

In this article, you’ve learned what dependency injection is, how to use it and when to use it. Awesome!

Want to learn more? Check out these resources:

Enjoyed this article? Please share it!

How To: Dependency Injection In Swift https://learnappmaking.com/dependency-injection-swiftClick To Tweet

Reinder de Vries

Reinder de Vries is a professional iOS developer. He teaches app developers how to build their own apps at LearnAppMaking.com. Since 2009 he has developed a few dozen apps for iOS, worked for global brands and lead development at several startups. When he’s not coding, he enjoys strong espresso and traveling.

Comments & Questions

Got a comment or question? Let me know! I read and respond to every one. Thanks!