Simple Dependency Injection using @propertyWrapper

Fernando Martín Ortiz
4 min readNov 4, 2019

Notes: This has already been posted on my personal blog.

TL;DR :: Here is the gist.

Dependency injection is critical to get a good-quality codebase. As misterious as it can sound, dependency injection is central in software architecture.

But, what is it exactly? Well, let’s explain it through an example. Let’s suppose we want to design a groceries store calculator. We want to sum all the products’ prices and then calculate the taxes to the sub-total. We’ll start with a module: ProductsCalculator, and a struct called Product.

This can work for a simple use case. But real world scenarios are hardly ever that simple. Out there, in the real world, we will find really strange logics that will change over time, and we need to be prepared for them. And our most important tool for this, is a good software architecture. To get a good architecture, we will need to decouple the code a bit by splitting it into modules. And a good option here is to create a TaxesCalculator object that can calculate the taxes to be applied. For example:

This way, we could change the code in TaxesCalculator without modifying ProductsCalculator. However, we can improve this design a lot. In first place, a good practice is to code against an interface and never against a concrete implementation. To apply this gold principle here, we would need to do something like this:

This way, we can vary the TaxesCalculatorType we are using without affecting the internal logic in ProductsCalculator. Each module knows only what is needs to know.

This code still has an important failure in its design… We are still instantiating the TaxesCalculatorType in the ProductsCalculator class, so it still has a strong dependency on the concrete implementation. And now is when Dependency Injection comes into the play.

We will need to inject the concrete TaxesCalculatorType object in the ProductsCalculator:

By injecting the TaxesCalculatorType in the constructor, we don’t have a dependency on the concrete implementation anymore.

To generalize, when you have two modules A and B, A has a dependency on B if it calls a method from B, or has a reference for B, or knows something about B. Then, we have two possiblities, A can either know exactly how to create B, and how to use it, or we can `inject` B into A. That’s what dependency injection (DI) is about: Don’t letting a module know all about its dependencies, but giving it its dependencies from the outside. That way, we can give it different objects depedending on the context.

Different ways to inject a dependency.

The four most common ways to inject a dependency are:

1. Using a method/property: We pass the concrete implementation by calling a method or setting a property in the class. For example:

2. Injecting in the constructor: We inject the dependency using the constructor, as seen in the first example.
3. Using a DI Container: This is more popular on other stacks (like Java, for example). We use a class called Container to register the dependencies at the beginning of the program, and then from the rest of the code we ask the Container to resolve which class should we use there.

Property Wrappers

Enough with Dependency Injection. Let’s talk about the other important part of this article: Property Wrappers.

Property Wrappers are a new addition in Swift 5. They let us “delegate” the access of a property to a struct that is annotated with @propertyWrapper. Let’s explain it with an example before jumping into dependency injection again: We want to have an array that is always sorted by a specific criteria.

So let’s see how we can use it:

Not that hard, huh? Another thing I haven’t said in the example is that all the properties that are annotated by a property wrapper need to be var. let isn’t allowed to be used with property wrappers.

So, what?

How are property wrappers related to Dependency Injection? They seem to be cool stuff but not related in any way so far. Yes, that can seem to be the case, but we can use property wrappers to inject dependencies from a DI Container.

Let’s see how this could work.

We will start by creating a NameContainer for the dependencies:

We need two more functions in the container:
- register: Adds a new entry for the dependencies registry. Optionally namespaced.
- resolve: It will return the needed dependency for the requested type. It can also work for namespaced dependencies.

Finally we need a property wrapper that can inject a dependency from the container in a property from an unrelated class. This property wrapper needs an optional argument for the dependency key and another optional argument for the DI container (it will default to the `default` singleton container).

Simple, right?

Let’s see how we can use this utility:

Conclusion

Dependency injection is a pattern that you will be using once and once again as a software designer. Normally, using just constructor-based DI will be enough. But having this simple alternative can be handy. Also, you have learnt one thing or two about property wrappers too.

Thank you!

Final Code

--

--