Dependency Injection in Swift with Property Wrappers

A Modern Approach to Dependency injection in Swift using Property Wrappers.

Ilario Salatino
The Startup
2 min readMay 14, 2020

--

In this article I will propose an approach to implement Dependency Injection in swift using the new Property Wrappers, without any external API.

Some Background

If you don’t know what dependency injection is or you’re looking for some more simple and quick approach, check out my previous article

So to explain why that approach is not good for every situation let’s show the example I’ve made there

And we inject the dependencies as follows

The Problem with This Approach

This Contstructor Injection would be good if we’re developing a small app, but imagine if our app gets bigger, we would introduce a lot of boilerplate code by calling all the initializers and constantly passing objects to the initializers.

With Swift 5.1 Property Wrappers were introduced, and they could help us to implement dependency injection with a different approach.

If you’re curious to know what property wrappers are and why they were introduced check the following link.

The proposed Solution

I know you’re pretty confused right now but I will show you step by step how I implemented dependency injection with a custom property wrapper

Let’s use again CoffeeMaker as an example to have a better understanding of the problem related to a real world use case.
We have our coffee maker which contains some components as a Pump and a Electric Heater.

Let’s define a Component protocol with a simple serve() function:

Let’s now create our coffee maker components:

And of course our CoffeeMaker class:

As you may have noticed, our components have the @inject annotation, that for those who are familiar with android and dagger2 is not completely new.

But where is that annotation coming from?

Here the Property Wrappers come to the rescue:

What’s happening here?

We’re creating a property wrapper that applies the previous logic to every property we flag with the @Inject annotation.
Based on the component type, our Resolver class will inject the right dependency into our CoffeeMaker.

The “resolve” method will basically return the right dependency from the factory dictionary that we will populate using the “add” method.

Let’s Make Some Coffee

All we have to do now is to register the correct dependencies into our Resolver and try to use our CoffeeMaker

And there’s the output:

I hope you enjoyed the Article, let me know if you have some different approach or any feedback, Thanks!

--

--