Types of Dependency Injection in Swift — with Testing Examples

Dependency Injection is an essential piece of knowledge for an iOS Developer nowadays. Therefore, it is very important to know how to implement it in Swift.

In this post, I won't explain deeply what it is or when to use it, but rather leave some material about it and provide some examples.

What is Dependency Injection?

Reading recommendations:
- Inversion of Control Containers and the Dependency Injection pattern
- DIP in the Wild

What are the advantages of using it?

It is essential when you are aiming for a testable code. Instead of using Singletons or making the objects create their own dependencies, you receive them from outside using a dependency injection technique. This makes testing a lot easier since you can create Test Doubles to control inputs and verify outputs of your code.

Some advantages:

  • Reduced coupling.
  • Flexibility, making your application more configurable. This means that we can have many concrete implementations, but the interface won't change.
  • Code reusability.
  • Better testability.
  • Makes the code easier to maintain in the long run.

In this article, I will present examples, succinct explanation, some tests, and discussion of the types of injection below:

  • Initializer-based
  • Property-based
  • Parameter-based

Initializer Based

With this technique, you will provide the object with everything it needs on its initialization.

Let's assume you are creating an ImagesService that uses Cache and a Network layer. With the initializer-based technique, it could be something like this:

Intializer-based example.

What about the tests? How this could be used on them?

Intializer-based test example.

Notice that the usage of default parameters on the init method can simplify ImagesService in the application, while also making it simple to accept test doubles injection.

Property-based

It consists of exposing your dependency with a public or internal access modifier to enable it to be assigned from outside. Which can be an option anytime you don’t have control over the initialization of the subject needing the dependency.

Note: This could come in handy when you have a legacy application and is starting to separate responsibilities on new components or dependencies.

Consider that you have some legacy code that does not use injection techniques, where everything happens on the controller and uses storyboards. In order to make its logic testable, you could use the technique explained above as shown below:

Before using dependency injection.
After applying Property-based injection.

How could we test it?

Testing our legacy code with property-based injection.

Parameter-based

Consists on using a parameter to inject your dependencies.

This turns out to be very useful also when dealing with legacy code since you can simply inject the dependency needed as a parameter and use a default value. Using this approach is many times less expensive than modifying the whole class to enable initializer or property-based injection.

Consider that we have another implementation of the ImageService, from the first example, but now implemented with static methods like below:

ImageService implemented with static methods.

Since this static approach doesn't have initializers, it could be very painful for us to change it's implementation all over the code using initializer or property-based injection… Taking that into account, a possible approach could be extracting interfaces for Cache and Network, as we did on the initializer-based example, passing the dependencies as a parameter with a default value.
The code would be something like:

ImageService refactored to use parameter-based injection.

This would not change the ImageService usage along with the legacy code but will enable us to take control over Cache and Network for our tests.
The tests will end up being something like the example below:

Conclusion

Knowing different dependency injection techniques will help you decide which one, or which combination of them is more suitable to your problem in order to create more testable, reusable, and maintainable code.

The Startup

Get smarter at building your thing. Join The Startup’s +724K followers.

Eduardo Sanches Bocato

Written by

iOS Engineer, AI enthusiast, Crossfit/Gymnastics. Currently working as iOS Lead @WarrenBrasil.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +724K followers.

Eduardo Sanches Bocato

Written by

iOS Engineer, AI enthusiast, Crossfit/Gymnastics. Currently working as iOS Lead @WarrenBrasil.

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +724K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store