Dependency Injection using Container in Swift
Dependency injection is not only known as achieving dependency inversion principle which we already know that from SOLID principle but also provides powerful unit testing. In this article, I will not explain that what is dependency injection and compare its advantages, disadvantages with singleton, I am going to focus a specific case which is we want to write unit test cases of our injected type and changing its state globally both. If you do not know dependency injection enough, please, check its topic before reading this.
Let’s say that we use the theme changing depends on the app is light or dark. Normally, as brute force solution, we use singleton pattern to write a class and manage its state from it. However, if we want to improve our code base as much as testable, we should use dependency inversion principle so dependency injection but it causes complexity between screens, modules. It may also cause inconsistency arising from complexity. To preventing this, we should create a container which contains unique types and we should put dependency injected types inside it. Of course, there are lots of solutions to do that such as using third party Swinject or without third party implementation. I preferred without third party implementation to explain it as much as basic.
As we can see in the sequence diagram above, the user register the current theme, change its state, push the detail screen respectively. After that, injected dependency read its latest value from the container and set the latest theme.
To achieve that, first of all, we need to create a property wrapper named Dependency to set and get the property to/from the container.
After that, we need to write a container that stores an unique identifier corresponds to the type.
The base implementation is done. Let’s look at the implementation of the screens now.
In the first screen, we changed the theme and navigate the detail screen without using initializer injection between screens. If our app has more screens this initializer injection causes complexity and inconsistency.
In the second screen, we just read and set current theme.
Using a container for dependency injection reduce complexity if you have to manage lots of screens like modular apps. This is the disadvantage of using dependency injection but we break this using the container at runtime.
Thanks for reading!