-
Notifications
You must be signed in to change notification settings - Fork 2
Types of Injections
In this section. . .
- Initializer Injection
- Property Injection
- Runtime Arguments
- Injecting the Assembly
- Circular Dependencies
All injections are defined within one or more PilgrimAssembly
sub-classes.
class QuestAssembly: PilgrimAssembly {
let childAssembly = ChildAssembly()
override func makeBindings() {
super.makeBindings()
makeInjectable(knight, byType: Knight.self)
makeInjectable(holyGrailQuest, byType: Quest.self)
makeInjectable(holyGrailQuest, byKey: "damselQuest")
importBindings(childAssembly)
}
func knight() -> Knight {
weakShared {
Knight(quest: damselInDistressQuest())
}
}
/**
HolyGrailQuest is a struct that conforms to the Quest protocol.
*/
func holyGrailQuest() -> Quest {
objectGraph {
HolyGrailQuest()
}
}
/**
Damsel's name is Bruce and the Knight is a lovely lass named Fiona.
*/
func damselInDistressQuest() -> Quest {
objectGraph(DamselInDistressQuest())
}
}
Also known as constructor injection. Here's how to do it:
func knight() -> Knight {
weakShared {
Knight(quest: damselInDistressQuest())
}
}
/**
HolyGrailQuest is a struct that conforms to the Quest protocol.
*/
func holyGrailQuest() -> Quest {
objectGraph {
HolyGrailQuest()
}
}
Create a function that returns emits a scoped (shared
, weakShared
, objectGraph
or unShared
) instance. Initializer injections can be specified as arguments pointing to other items within the assembly, or in a child assembly.
func addCityViewController() -> AddCityViewController {
objectGraph(AddCityViewController(nibName: "AddCity", bundle: Bundle.main)) { [self]
(controller: AddCityViewController) in
controller.cityDao = coreComponents.cityRepository()
controller.weatherClient = coreComponents.weatherClient()
controller.theme = themeAssembly.currentTheme()
controller.rootViewController = rootViewController()
}
}
Property injection is done in the configuration closure. In general favor initializer injection over property injection, since initializer injection allows emitting an immutable fully-configured and fail-fast class or struct.
Besides performing injections in the configuration closure, a function can be invoked, for example to validate that the instance is in a required state.
Run-time arguments allow defining a factory on the assembly. Here is an example:
func userDetailsController(user: User) -> UserDetailsController
{
objectGraph {
UserDetailsController(user: user, photoService: self.photoService())
}
}
The factory pattern is a practice to create objects that mix static dependencies and parametrization. Factories also allow "hiding" dependencies of created objects, which the creator does not have to care about. Combined with Injecting the Assembly itself we can use Pilgrim as a factory for emitting built instances with a mixture of dependencies defined within the composition root and runtime parameters.
For example, we can obtain a UserDetailsViewController with both the static and runtime dependencies as follows:
@Assembled var assembly : ApplicationAssembly
func userDidLogin() {
let detailsController = assembly.userDetailsController(user: currentUser)
}
A pilgrim assembly can be injected itself. This is useful with runtime arguments, where the assembly acts as a factory.
func rootViewController() -> RootViewController {
shared(RootViewController(mainContentViewController: weatherReportController(), assembly: self))
}
In the example above, the root view controller can use the assembly to build a child controller with a mixture of runtime and static dependencies.
@Assembled
property wrapper.
Optionally, the assembly can be backed by a protocol that represents the factory methods.
Sometimes you wish to define objects that depend on each other. For example a ViewController that is injected with a view, and a View that is injected with the ViewController as a delegate.
Pilgrim supports circular dependencies via property injection.
func weatherReportController() -> WeatherReportViewController {
objectGraph(WeatherReportViewController(view: weatherReportView(),
weatherClient: coreComponents.weatherClient(), weatherReportRepo: coreComponents.weatherReportRepository(),
cityRepo: coreComponents.cityRepository(), assembly: self))
}
func weatherReportView() -> WeatherReportView {
objectGraph(WeatherReportView(frame: CGRect.zero)) { [self] (view: WeatherReportView) in
view.theme = themeAssembly.currentTheme()
view.delegate = weatherReportController() // Circular dependency
}
}
Something still not clear? How about posting a question on StackOverflow.
Get started in two minutes.
Get familiar with Pilgrim.
Become a Pilgrim expert.
For contributors or curious folks.