Other Classes
The following classes are available globally.
-
A
DependencyContainer
is used to create and access instances of services that the SDK needs in a configurable way, using inversion of control (IoC).Container
Interactions with dependencies will happen through a container. You start by creating one (or multiple) containers to register services required for booting the framework or application.
let container = DependencyContainer()
Factory
The most common method for registering dependencies is by associating a protocol or type to a factory. This will ensure a new instance of your dependency is created everytime it is resolved.
container.register { ServiceImplementation() as ServiceInterface }
It is also possible to explicitly define the type as argument.
container.register(as: ServiceInterface.self) { ServiceImplementation() }
Resolution
You can resolve a concrete instance of protocol or type using the container.
let object = try! container.make() as ServiceInterface
It is also possible to specify the type in parameter instead.
let object = try! container.make(ServiceInterface.self)
Warning
The order in which dependencies are registered is not relevant, as long as:- your dependencies resolve types that have been registered previously
- you don’t register a dependency for a type already registered
Note that overriding dependency registrations may be desired to allow custom injections replacing default types for example, but you must then carefully check the order of registrations.
Scopes
Singleton Instance
You can also register an initialized instance of a dependency, which will be reused by the container while resolving the dependency.
container.register(ServiceImplementation(), as: ServiceInterface.self)
Or specify the
singleton
scope while registering a factory, which will resolve the factory only once and then reuse the same instance.container.register(.singleton) { ServiceImplementation() as ServiceInterface }
Shared Instances
Sometimes you need to register different factories or different implementations of the same protocol. By default, if you register a dependency for the same type multiple times, the latest definition will override a previous one. This is called the
unique
scope.To solve that, you can use shared dependencies by providing a
shared
scope with a specific context to theregister
method:container.register(.shared(.myContext)) { ServiceImplementation() as ServiceInterface } container.register(.shared(.anotherContext)) { ServiceImplementation() as ServiceInterface }
When you provide a context to resolve, container will look for a dependency associated with this context:
let object = try! container.make(ServiceInterface.self, context: .myContext) let anotherObject = try! container.make(ServiceInterface.self, context: .anotherContext)
Dependency Provider
In order to organize dependencies in a better way, you can use multiple
DependencyProvider
to register all dependencies you would like to provide.
See morelet networkingProvider = NetworkingDependencyProvider() let securityProvider = SecurityDependencyProvider() container.register(providers: [ networkingProvider, securityProvider ])
Declaration
Swift
public final class DependencyContainer : DependencyResolver
extension DependencyContainer: CustomStringConvertible