-
Notifications
You must be signed in to change notification settings - Fork 72
Auto wiring
When you use constructor injection to inject dependencies of your component and they are also registered in the container auto-wiring enables you to resolve these components just with one call to resolve
method without providing its dependencies as arguments or without explicitly resolving them inside the definition's factory. Instead container will resolve them for you.
class PresenterImp: Presenter {
init(view: ViewOutput, interactor: Interactor, router: Router) { ... }
...
}
container.register { RouterImp() as Router }
container.register { View() as ViewOutput }
container.register { InteractorImp() as Interactor }
container.register { PresenterImp(view: $0, interactor: $1, router: $2) as Presenter }
let presenter = try! container.resolve() as Presenter
Auto-wiring uses Swift Type Inference to infer types of constructor arguments and if they all are registered in container, they will be automatically resolved.
Note: it also can handle optional dependencies
At the same time you are able to resolve the component using runtime arguments:
let view = try! container.resolve() as ViewOutput
let interactor = try! container.resolve() as Interactor
let router = try! container.resolve() as Router
//without auto-wiring
let presenter = try! container.resolve(withArguments: view, interactor, router) as Presenter
Auto-wiring saves all these calls to resolve each constructor argument.
Alternatively you could register factory that does not accept runtime arguments but explicitly resolves constructor arguments:
container.register {
try PresenterImp(
view: container.resolve(),
interactor: container.resolve(),
router: container.resolve()
) as Presenter
}
In this case auto-wiring again lets you avoid this repetitive calls to resolve
method inside the factory.
If you try to resolve type using auto-wiring and named definition the tag that you use to resolve will be implicitly used to resolve all the constructor dependencies. That can lead to unexpected not shared dependencies in the graph.
container.register() { ServiceImp(
config: $0 as Config,
dataStore: $1 as DataStore) as Service
}
container.register(tag: "dev") { DevConfig() as Config }
container.register(tag: "prod") { ProdConfig() as Config }
container.register(.singleton) { DataStore() }
let devService = try! container.resolve(tag: "dev") as Service
let prodService = try! container.resolve(tag: "prod") as Service
devService.config !== prodService.config //expected
devService.dataStore !== prodService.dataStore //not expected
To avoid that resolve these dependencies explicitly:
container.register() { try ServiceImp(
config: $0 as Config,
dataStore: container.resolve() as DataStore) as Service
}
container.register(tag: "dev") { DevConfig() as Config }
container.register(tag: "prod") { ProdConfig() as Config }
container.register(.singleton) { DataStore() }
let devService = try! container.resolve(tag: "dev") as Service
let prodService = try! container.resolve(tag: "prod") as Service
devService.config !== prodService.config //still different instances as expected
devService.dataStore === prodService.dataStore //shared instance now