什么是Wormer?
Wormer是一个轻量级且简单的依赖注入框架,用Swift编写,并更新到了语言的4.2版本。
它自由地受到了Unity的启发,这是一个为.NET平台的开源DI容器(不要与Unity游戏引擎混淆)。
Wormer使用静态声明式方法将接口与其实现链接起来。一个接口通常是一个协议,但它也可以是一个基类,而一个实现是一个采用该接口的类或结构体,理想情况下,它也可以是任何采用接口协议的值类型。
依赖注入容器通过Injector
类访问,该类公开一个default
静态属性。如果你想知道,是的,它使用了单例模式。初始化器被声明为私有,以防止直接实例化。
如何使用它
将接口与其实现绑定
给定一个接口
protocol Interface {}
以及一个实现了该接口的类
final class Implementation : Interface {}
通过调用bind
方法建立链接
Injector.default.bind(interface: Interface.self, toImplementation: Implementation.self, asSingleton: false, initializer: { Implementation() })
《asSingleton》属性指定,当设置为true
时,应该创建单个实例并始终返回,模仿单例模式。如果设置为false
,则在任何调用instance()
时创建新实例(请参阅下面的说明)。
最后一个参数initializer
是一个闭包,必须创建并返回实现类型的实例。请注意,此闭包在内部存储,因此维护强引用。
获取与接口绑定的实例
将接口绑定到实现后,通过调用instance(for:)
方法获取新的(或单例情况下的缓存的)实例
let instance = Injector.default.instance(for: Interface.self)
还有instance(for:)
的一个重载版本,它利用接口类型的类型推断
let instance: Interface = Injector.default.instance()
警告:两个实现都内部使用强制解包来将接口转换为实现。如果没有将接口绑定到实现,这将导致运行时异常。有一个更安全的方法可用,它不使用强制解包,而是返回一个可选值
public func safeInstance<P>(for interfaceType: P.Type) -> P?
注释
- 接口只能绑定到一个实现
- 一个实现可以被多个接口绑定
如何使用
绑定
通常在应用启动时进行,因此最佳位置可能是application(didFinishLaunchingWithOptions:)
。我有种良好的习惯,不滥用该方法,因此我通常会创建一个外部结构(或枚举)并具有静态方法,用于完成所有初始化。
enum DependencyBuilder {
static func build() {
let injector = Injector.default
/// 1
injector.bind(interface: EventBus.self,
toImplementation: EventBusImplementation.self, asSingleton: true) {
EventBusImplementation()
}
let eventBus: EventBus = injector.instance()
/// 2
injector.bind(interface: NotificationGateway.self,
toImplementation: NotificationGatewayImplementation.self, asSingleton: true) {
NotificationGatewayImplementation(eventBus: eventBus)
}
/// 3
injector.bind(interface: NearableProximityProvider.self,
toImplementation: BrandedNearableProximityProvider.self, asSingleton: false) {
BrandedNearableProximityProvider()
}
}
}
上述代码创建了三个绑定
EventBus
绑定到EventBusImplementation
,启用单例NotificationGateway
绑定到NotificationGatewayImplementation
,启用单例。注意初始化器要求一个EventBus
实例- 《NearableProximityProvider》绑定到《BrandedNearableProximityProvider》,不使用单例模式,因此在每次调用
instance()
时都会创建一个新的实例。
获取实例
如前一段所述,通过使用 instance()
方法或其 instance(for:)
重载来获取绑定到接口的实例。
有 2 种方式可以注入依赖
- 在初始化器中
- 通过属性
在所有情况下,我通常更倾向于使用前者,除非无法定义新的初始化器——一个典型的例子是 UIViewController
,其生命周期通常不在我们的控制范围内,以及用于实例化的初始化器。
初始化器注入
假设有一个类或结构体如下
struct SomeProvider {
private var eventBus: EventBus
init(eventBus: EventBus) {
self.eventBus = eventBus
}
}
它接受一个 EventBus
作为初始化参数。要创建一个实例
let eventBus: EventBus = Injector.default.instance()
let provider = SomeProvider(eventBus: eventBus)
属性注入
当无法创建初始化器时,那么在 Wormer 中,属性注入是唯一的替代方案,至少是一种选择。以下是如何实现它
class EventViewController : UIViewController /* NSViewController */ {
private lazy var eventBus: EventBus = Injector.default.instance()
}
EventViewController()
如您所见,我更喜欢延迟初始化,以确保仅在需要时才进行实例化。
安装
支持的平台
- iOS: 支持
- macOS: 目前不支持
- watchOS: 目前不支持
- tvOS: 目前不支持
Cocoapods
pod `wormer`
Carthage
抱歉,目前不可用(求帮助!!)
手册
复制 Wormer.swift
文件并将其粘贴到您的项目中。
许可
MIT 许可。阅读 LICENSE
文件。