I have a dependency container, that looks like this -
public protocol DependencyContainer {
typealias FactoryClosure = (Self) -> AnyObject
func register<Service>(type: Service.Type, closure: @escaping FactoryClosure)
func resolve<Service>(type: Service.Type) -> Service
}
public final class CoreDependencyContainer: DependencyContainer {
private var services: Dictionary<ObjectIdentifier, FactoryClosure> = [:]
public func register<Service>(type: Service.Type, closure: @escaping FactoryClosure) {
services[ObjectIdentifier(type)] = closure
}
public func resolve<Service>(type: Service.Type) -> Service {
if let service = services[ObjectIdentifier(type)]?(self) as? Service {
return service
}
preconditionFailure("Could not resolve service for \(type)")
}
}
I have some services registered as follows:
dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
let httpClient = container.resolve(type: HTTPClient.self)
return RemoteImageDataLoader(client: httpClient)
})
I want to however register 2 services that conform to the abstract type RemoteImageDataLoader
.
dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
let httpClient = container.resolve(type: HTTPClient.self)
return RemoteImageDataLoader(client: httpClient)
})
dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
let httpClient = container.resolve(type: AuthenticatedHTTPClient.self)
return RemoteImageDataLoader(client: httpClient)
})
This obviously wont work as the second entry would replace the first in the services
dictionary.
I tried to create a typealias
to use instead, however this does not work.
dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
let httpClient = container.resolve(type: HTTPClient.self)
return RemoteImageDataLoader(client: httpClient)
})
typealias AuthRemoteImageLoader = RemoteImageDataLoader
dependencies.register(type: AuthRemoteImageLoader.self, closure: { container in
let httpClient = container.resolve(type: AuthenticatedHTTPClient.self)
return RemoteImageDataLoader(client: httpClient)
})
How can I register the 2nd dependency in this case?
I'd like to avoid creating 2 versions of RemoteImageDataLoader
as the only difference is the injected HTTPClient
instance.
It doesn't work current as you are using ObjectIdentifier
as a key in your dictionary, which the typealias
does not change.
You are basically registering the same object twice.
Create an empty protocol that conforms to the same interface. You will also need to extend your to conform to your new, empty interface otherwise your resolve
method will throw a preconditionFailure
protocol AuthRemoteImageLoader: RemoteImageDataLoader { }
extension RemoteImageDataLoader: AuthRemoteImageLoader { }
You could also consider using generics to specify the HTTPClient
interface being used, and extend RemoteImageDataLoader
to act accordingly based on the type of client.