-
Notifications
You must be signed in to change notification settings - Fork 2
Property Wrapper
Given an assembly with bindings:
override func makeBindings() {
super.makeBindings()
makeInjectable(knight, byType: Knight.self)
}
We can inject built instances into top-level classes using the @Assembled
property wrapper, as follows:
class StoryViewController : UIViewController {
/**
The built instance is auto-injected from the QuestAssembly
*/
@Assembled var knight: Knight;
private(set) var story: Story
init(story: Story) {
self.story = story
}
}
Pertinent points to note are:
- Pilgrim is a DI
container
and the@Assembled
property wrapper is a convenient way to obtain built instances, and inject them as dependencies into top-level components. - Use the assembly to define how components interact. For example a Quest is injected into a Knight - this happens within the assembly.
- Use the Assembled property decorator to obtain built instances for injection into top-level components - eg a view controller, in a UIKit app.
The default assembly is specified when an application is bootstrapped, for example in UIApplicationMain
:
class PocketForecastApplication: UIApplication {
override init() {
AssemblyHolder.defaultAssemblyType = ApplicationAssembly.self
}
}
When the default assembly is not set, or we wish to explicitly override, it can be specified as follows:
@Assembled(assembly: QuestAssembly.self) var knight: Knight
In general we bind by type, for example a protocol to a concrete implementation:
override func makeBindings() {
super.makeBindings()
makeInjectable(weatherClient, byType: WeatherClient.self)
}
func weatherClient() -> WeatherClient {
objectGraph {
WeatherClientWorldWeatherImpl(reportRepo: weatherReportRepository(), serviceUrl: config.serviceUrl,
daysToRetrieve:config.daysToRetrieve, apiKey: config.apiKey)
}
}
When necessary, for example if we have two implementations representing the same protocol, we can bind to a string key:
makeInjectable(holyGrailQuest, byKey: "holyGrailQuest")
A binding for the assembly is made by default, so give the following:
class QuestAssembly: PilgrimAssembly {
override func makeBindings() {
super.makeBindings()
makeInjectable(knight, byType: Knight.self)
makeInjectable(holyGrailQuest, byType: Quest.self)
}
func knight() -> Knight {
objectGraph(Knight(quest: holyGrailQuest()))
}
/**
HolyGrailQuest is a struct that conforms to the Quest protocol.
*/
func holyGrailQuest() -> Quest {
shared(HolyGrailQuest())
}
}
We can obtain the assembly using:
@Assembled var assembly: PilgrimAssembly
This is useful when using the assembly as a factory with runtime-arguments.
We can manually bind an assembly with a protocol. Say we create a ViewCoordinator
protocol representing a factory that can emit view controllers:
public class ApplicationAssembly: PilgrimAssembly, ViewCoordinator {
public override func makeBindings() {
makeInstanceInjectable(self, byType: ViewCoordinator.self)
}
}
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.