Dependency injection in Swift made easy!

Jason Meulenhoff
ITNEXT
Published in
3 min readMay 24, 2020

--

Photo by Hitesh Choudhary on Unsplash

Greetings all, I have been absent for a while due to work keeping me busy.

Today I want to write something about a “new” exciting feature in Swift 5.1 called Property Wrappers. With this “new” feature, we can make a small (140 lines) dependency injection library using some fancy DSL builders.

Here at Pinch, we use construction injection to satisfy all our dependencies; This gets tedious fast if we have many properties that we have to pass around. We have tried some open-source frameworks; somehow, we always came back to constructor injection.

With this new feature implemented into Swift, I wanted to give my implementation a spin. The following snippet is the end goal i’d like to achieve. Ensure that the code is in one file; this makes us able to hide some implementation logic within the library.

We use a custom wrapper to inject our dependency right into our ViewController. The constraints should be solved automagically.
We can start by creating a class that can hold all our dependencies.

We create a dictionary that can hold all our factories so we can have a lookup table to create instances as we please. We do need to make sure to make the constructor private; this forces us to use the DSL that we are going to build later on.

When the object deinitializes, we make sure to remove all the factories from memory.

With our base implemented, we create a service that holds the inner workings. It allows for the creation of instances and sets a cycle either “global” or “oneOff”; this means that we always return the same instance when we request one or create a new one every time it’s accessed.

With the basics implemented, we can make a private extension on our dependencies class. So it can handle registration and resolving of our dependencies.

This code will benefit from error handeling ❤

In the resolve method, we create an ObjectIdentifier based on the service we are requesting. We do some checks to see if we require a global instance and act accordingly.

The register method saves the service (based on the ObjectIdentifier) to the dictionary.

Its time to create a public extension. we create a static main variable that will hold our static instance. This is needed to make our property wrapper easily resolve our dependencies

This code will benefit from error handeling ❤

Its time to create a public extension.

We create a fileprivate static variable that holds our “main” instance; This allows the property wrapper to resolve our dependencies quickly. We create some DSL methods that accept services and create some convenience initializers. Finally, we create a build method that replaces the main instance with a new version.

All that’s left is to implement our property wrapper.

This code will benefit from error handeling ❤

We store a reference to our resolved dependency inside our wrapper (This makes sure that when we access our variable, it’s not resolved into a new instance every time).

When we access our variable, we first check if we already created an instance before otherwise return it. If this is the first time, we call our closure to resolve the dependency.

Let’s see if our implementation works. Imagine the following scenario with the following dependency graph.

When we run the example, we can see that our implementation is working!

Voila, this concludes my deep-dive into the new property wrappers introduced in Swift 5.1. This example lacks basic error handling and probably can be improved but should give you insights on how to write your own.

Do you have any questions or remarks? Let us know in the comments.

--

--