轻量级的依赖注入容器,具有简洁的流畅接口。
使用 Swift 包管理器
dependencies: [
.package(url: "https://github.com/andrey-shavelev/Juice", from: "0.1.0")
//...
]
let container = try Container { builder in
// register a type that conforms to Injectable protocol
builder.register(injectable: FreshJuice.self)
.instancePerDependency()
.as(Juice.self)
// register by initializer
builder.register(initializer: Apple.init(color:))
.instancePerDependency()
.asSelf()
// register a custom factory
builder.register { scope -> TeaBlend in
let orange = try scope.resolve(Orange.self)
let blackTea = try scope.resolve(BlackTea.self)
return TeaBlend(fruit: orange, tea: blackTea)
}
.singleInstance()
.asSelf()
}
// required
let orangeJuice = try container.resolve(Juice.self)
// optional
let compot = try container.resolveOptional(Compot.self)
let tea = try container.resolve(Tea?.self)
// supplying arguments
let appleJuice = try container.resolve(
Juice.self,
withArguments: Apple())
// or when you need to specify type directly
let appleJuice = try container.resolve(
Juice.self,
withArguments: Argument<Fruit>(Apple()))
传递给 resolve
方法的参数会通过类型与初始化器的参数匹配,并且优先于容器中注册的服务。
对于符合 Injectable
协议之一的服务,或者通过它们的 init
方法注册的服务,初始化器的参数将由 Container
填充。
class IcyLemonade: InjectableWithFiveParameters {
let fruitJuice: Juice
let lemon: Lemon
let optionalSweetener: Sweetener?
let water: Water
let ice: Ice
// All parameters will be filled by Container from resolution scope.
required init(_ fruitJuice: Juice,
_ lemon: Lemon,
_ optionalSweetener: Sweetener?,
_ water: Water,
_ ice: Ice) {
self.fruitJuice = fruitJuice
self.lemon = lemon
optionalSweetener = optionalSweetener
self.water = water
self.ice = ice
}
}
let container = try Container { builder in
builder.register(injectable: IcyLemonade.self)
.singleInstance()
.asSelf()
///...
}
或者,依赖项可以注入到属性中。
// Using Inject property wrapper
class Jam {
@Inject var fruit: Fruit
@Inject var spice: Spice?
init() {
}
}
// Or without wrapper
struct TeaBlend {
var fruit: Fruit!
var spice: Spice?
init() {
}
}
// In this case you need to specify properties for injection when registering a service
let container = try Container { builder in
builder.register(injectable: Jam.self)
.singleInstance()
.asSelf()
.injectDependency(into: \.fruit)
.injectDependency(into: \.spice)
}
class Egg {
unowned var chicken: Chicken
required init(_ chicken: Chicken) {
self.chicken = chicken
}
}
class Chicken {
var egg: Lazy<Egg>
required init(_ egg: Lazy<Egg>) {
self.egg = egg
}
}
/*
* Lazy<T> - is a wrapper that delays actual resolution
* until its value is requested.
* For this purpose it keeps a strong reference to a resolution
* context of the owning instance,
* including all arguments (if any) that were passed to it.
*/
let container = try Container { builder in
builder.register(module: FruitModule())
}
// Module allows to group registrations
struct FruitModule : Module {
func registerServices(into builder: ContainerBuilder) {
builder.register(injectable: Apple.self)
.instancePerDependency()
.asSelf()
builder.register(injectable: Orange.self)
.instancePerDependency()
.as(Fruit.self)
}
}
let container = try Container { builer in
// Some types are registered here
}
let childContainer = try container.createChildContainer { builer in
// Additional types are be registered here
// Registrations from the parent container could be overriden
}
当前版本的 Juice 不支持从并发线程解析服务。
let container = try Container { builder in
// Instance per depenedency
builder.register(injectable: Banana.self)
.singleInstance()
.asSelf()
// Each time Banana is resolved, container will return the same instance. Container will keep strong reference to it.
// Single instance
builder.register(initializer: Apple.init(color:))
.instancePerDependency()
.asSelf()
// Each time Apples is resolved, container will create a new instance. Container will not keep reference to any of it.
// External singletons
let someExternalSingleton = SingletonService.instance
builder.register(instance: someExternalSingleton)
.ownedExternally()
.asSelf()
// For instances registered as ownedExternally() container will keep an unowned reference.
let anotherExternalSingleton = AnotherSingletonService.instance
builder.register(instance: anotherExternalSingleton)
.ownedByContainer()
.asSelf()
// For instances registered as ownedByContainer() container will keep a strong reference.
}
本项目使用 MIT 许可证。