Annotation Injection with compile-time safety in Swift

Arash Goodarzi ( Mehrdad)
2 min readAug 5, 2022

--

Let’s say we’re all familiar with the concept of dependency injection and why we tend to consider that. Also assume that we’re on the same page not to implement DI traditionally by initializer injection, property injection and method injection.

So here we will directly ship to the other options and we won’t talk about reasons of using DI.

Possible Choices

After a search, possible choices would be some third-party libraries which have their owns disadvantages. For instance, run-time based tools like Swinject and Resolver seems to be handy but having run-time registration process would lead to error-prone situation. After that we decide to choose something like Needle, providing compile-time safety. But the problem with needle is lots of boilerplate codes and its hierarchical structure. so we may choose something else.

What to do?

Now we want to have our own implementation of DI providing:

  • Compile-time safety.
  • Less boilerplate code
  • Syntactic sugar like annotations in Resolver.
  • No dependency to third-parties

Get Started

suppose we have these services to inject.

Note that Services should be constructed by some factories.

In the factories scope of the objects would be defined. for instance, we prefer NetworkService to be app-scoped like scope(.application) in Resolver and ConverterService to be created every single time it is called like scope(.unique) in Resolver.

Wrapping services into factories helps to define object scopes.

Then there should be a container to hold the factories. the container would be the end point which provides our services.

To use container in the annotations defining by swift property wrappers, we need to have accessibility to the container in the property wrappers. So a DIManager would be defined to provide the accessibility.

Almost there

Now let’s make our annotations by the DIManager as below:

Usage

In the end will inject our services by the annotations in MyViewModel:

easy-peasy!

Testing

After all, the injected MyViewModel should be testable. To test the viewModel by a mocked service we should mock the factory of the service and pass it to the container.

done!

You can find the source code in this repo:

hope find it useful.

--

--