Resolve your dependencies with Resolver

Photo by Ryland Dean on Unsplash

Introduction

But if there are also developers taking part in the discussion that do not just do iOS development they might get a bit confused that the discussion just has come up or they ask why you have not used it all along.

First I want to clearify that one always uses dependency injection when doing object oriented programming. You cannot get around it. Because dependency injection in its rawest form simply means that you hand an object the dependencies it needs. Meaning, every time when you have an object with properties and an initializer and this initializer has some arguments you are doing dependency injection (constructor injection).

The discussion usually comes up because it is easier for everybody working on the project if you use a consistent way of providing your objects with their needed dependencies.

In most larger projects you will have objects of which you want to use the same instance in multiple other objects or you want use something like a stateless service that is initialised every time it is used as an initializer argument.

When doing so it is easy to end up with many objects that all use the same instances of multiple objects which have other objects as their dependencies and so on. This then leads to having to carry all of those objects around and handing them from object to object, even though, you might not use all those objects at all places.

To keep sanity when handling dependencies and to keep the code base easier to maintain in regards to handling dependencies, many people use dependency injection frameworks. Frameworks that handle the initialisation of objects and the initialisation of the dependencies for you. Usually, they also provide you with a scoping meachnism. Meaning, that you can clearly state in which part of your app which objects need to be available (initialised). In addition to that you can usually have containers to separate dependencies based on the part of the app they are used in.

Whether you use a dependency injection framework or use your own strategy, using consistent dependency injection brings in general several advantages:

  • Decoupling of repsonsibilities & Reusability of code is increased
  • Refactoring is easier
  • Testing is easier (easier to replace dependencies with mock objects)

Today I want you to give you a short introduction to a dependency injection framework that I have been using for the last couple of months. Resolver.

It is a very light weight framework that is written in Swift and very well maintained. It is still quite new and easy to integrate into your project. If you do not want to refactor your whole code base at once, you can also start adding it incrementally which is very convenient.

Add Resolver to your project

According to the their GitHub page you can add Resolver with CocoaPods, Carthage or SwiftPackageManager.

What dependency injection in general makes easier and what Resolver makes it a no brainer is controlling that types either use the same instances of other types or new ones.

Sometimes it is necessary to use the same instance of e.g. some kind of service through out your app because a lot of other types need to access properties/ methods of that type and then you need to ensure that every type actually uses the sames instance of that type. Other times you want to ensure that all types use a different instance of some other type. In that case you need to make that sure as well.

To organise your dependencies Resolver makes it possible to add different containers. Those containers hold different dependencies for different parts of your app. It makes sense to have one general container. Let’s call it Application+Injection.swift.

In this file you can register all your dependencies.

When programming in Swift I like the protocol oriented approach, so you can register dependencies as shown above.

This file functions as your main container.

You can add all dependencies in this one file. But you can also split them app and add them to different containers (or you could also call it a name space) to group them more together. This can help you make clearer in which part of your app dependencies are/ should be used.

If you want to add a new container you would simply add a new file

Then you need to add this container to your main container. Like so:

To ensure that either all types use the same instance of a type or always a new one, Resolver provides so called scopes.

In the example above we define we want to always use the same instance of Dependency2 by defining the scope applicationand that we want to use a new instance for Dependency by defining the scope unique.

Resolver provides even more scopes to give you full control of how your dependencies are injected.

In general there are many different strategies you can use to inject dependencies into your types. In this article I will show you two different strategies that I used when I used Resolver in a project.

Initializer based injection

As you can see, we simply need to import Resolver and can resolve the dependency by simple calling Resolver.resolve() or when we want to resolve a dependency we have registered not in the main container we call Resolver.partOfYourApp.resolve().

Since you have defined the type of your argument, Resolver knows which type to resolve from the container.

Property based injection

Summary

--

--

blog.rebekkaorth.com

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