Learning software engineering is a process of biting your tongue. You learn a new concept and revel in the abilities it gives you, and then shortly thereafter, you’re looking at your old code thinking, “did I write that?” As a nine-month-old iOS developer, I’m still learning tons.
When I started, I saw singletons in iOS as a good thing. They are easy to use (pretty much one line of code and you can access your class anywhere), but they come with a lot of baggage. I don’t hold the view that singletons are to be completely avoided, but they should be carefully considered.
The main reason I try to avoid singletons now is because the code using the singleton now has a dependency on the singleton class. If the singleton class changes, it has to be swapped out everywhere it’s used. Additionally, singletons make testing difficult, because they have to be spun up when testing classes that use them. Sometimes, this may not be possible in the testing context, and now you’re stuck with untestable code.
Dependency injection to the rescue. I started learning about dependency injection while working on a Java Spring Boot application (dependency injection is a core concept in Spring) in my day job. Dependency injection requires you to pass dependencies used by the calling class through the constructor; alternatively, the dependencies can be properties of the class and set by a dependency injection framework.
Now, since we pass the dependency through the constructor, we could pass a mock class through the constructor too that is the same type as the dependency, allowing us to test the class without spinning up an instance of the actual dependency. Usually, your dependencies are based off a protocol in Swift (or interface in Java), which allows you to easily create mock classes for testing purposes. Ah, finally your code can be testable again.
Dependency injection isn’t a complex subject, you just need to get in the mindset of using it, and you will reap the rewards.
Matt from The Bunch