In software engineering, dependency injection is a technique in which an object receives other objects that it depends on. These other objects are called dependencies. In the typical “using” relationship the receiving object is called a client and the passed (that is, “injected“) object is called a service.
The code that passes the service to the client can be many kinds of things and is called the injector. Instead of the client specifying which service it will use, the injector tells the client what service to use. The “injection” refers to the passing of a dependency (a service) into the object (a client) that would use it.
The service is made part of the client’s state. Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.
Dependencies can be injected into objects by many means (such as constructor injection or setter injection).
Some simplistic examples:
Dependencies are passed via initializer. *Useful when the number of dependencies is low or the object needs to be immutable. Ensures that client object is always in a valid state but Dependencies cannot be changed later and becomes cumbersome with more than 3 dependencies. Consider property injection in this case.
Dependencies are passed via properties. Useful when dependencies need to be changed later or you do not directly initialize the object. View controllers is an example of the latter.
This method allows to set dependencies after instantiation and provides readable way of constructing objects with many dependencies. But the object might not be perfectly encapsulated and some dependencies could be missing, it also force the use of optional or force unwrapped properties.
There are other techniques not covered on this post, like Interface Injection or Ambient Context.
The Factory pattern is very convenient when injecting dependencies.
The main benefit of the Dependency Injection is that classes are more loosely coupled (without forcing those classes to be responsible for those objects), because they do not have hard-coded dependencies. This follows the Dependency Inversion Principle, one of the SOLID principles.
So in the end Dependency injection is just a technique for achieving loose coupling between objects and their dependencies. Rather than directly instantiating dependencies that class needs in order to perform its actions, dependencies are provided to the class (most often) via constructor injection.