AnnotationInject
生成您的依赖注入。旨在确保安全性。
AnnotationInject | |
---|---|
让您从手动注册依赖中解脱出来。 | |
将更多时间用于编码,而非配置时间!减少配置时间并专注于代码。 | |
避免运行时崩溃,依赖项未更新。所有检查均在 编译时 完成。 | |
基于您喜欢的开源工具 Sourcery 和 Swinject 构建。 | |
100% 开源,受 MIT 许可证保护 |
特定版本的文档可能略有不同。如果您有任何问题,请首先检查发布的文档(通过在 Github 上选择分支/标签)。
注入问题的原因是什么?
没有注解
在使用依赖注入库(例如,Swinject)时,您需要 记住 注册您的依赖项
container.register(CoffeeMaker.self) { r in
return CoffeeMaker(heater: r.resolve()!) // Trouble ahead, not sure Heater is in fact registered!
}
/// later in your code
let coffeeMaker = container.resolve(CoffeeMaker.self) // crash, missing Heater dependency!
运行这段代码可能会在 运行时 出现崩溃:我们没有注册任何 heater
,导致 CoffeeMaker 解析器崩溃。
包含注解
注解将生成您的依赖,并确保所有内容在编译时都能解析。
/// sourcery: inject
class CoffeeMaker {
init(heater: Heater) {
}
}
这次我们会得到一个编译时错误,因为我们忘记声明一个 Heater
依赖。好极了!
使用方法
1. 注解您的依赖
/// sourcery: inject
class CoffeeMaker {
init(heater: Heater) { }
}
/// sourcery: inject
class Heater {
init() { }
}
2. 添加生成依赖的构建阶段
有关详细信息,请参阅安装
如果无法解析所有依赖项,则会失败构建阶段,阻止代码成功编译。
3. 添加生成的文件并使用生成的代码
let resolver = Assembler([AnnotationAssembly()]).resolver
// `registeredService` is generated code. It is completely safe at compile time.
let coffeeMaker = resolver.registeredService() as CoffeeMaker
let heater = resolver.registeredService() as Heater
安装
注意:AnnotationInject需要Sourcery来进行注解声明,Swinject作为依赖注入器。
- Swift包管理器
dependencies: [
.package(url: "https://github.com/pjechris/AnnotationInject.git", from: "0.6.0")
]
然后为您的项目添加一个构建阶段
swift run annotationinject-cli --sources <path to your sources> --output <path to output generated code> (--args imports=<MyLib1> -args imports=<MyLib2>>)
- CocoaPods
将 pod AnnotationInject
添加到您的 Podfile
中并在项目中添加一个新的 构建阶段
"$(PODS_ROOT)"/AnnotationInject/Scripts/annotationinject --sources <path to your sources> --output <path to output generated code> (--args imports=<MyLib1> -args imports=<MyLib2>>)
注意:您可以将所有
sourcery
命令行选项传递给annotationinject
脚本。
- 手动操作
sourcery --templates <path to copied templates> --sources <path to your sources> --output <path to output generated code> (--args imports=<MyLib1> -args imports=<MyLib2>>)
可用注释
inject
将类注册到依赖注入容器中。
/// sourcery: inject
class CoffeeMaker { }
生成的代码
container.register(CoffeeMaker.self) {
return CoffeeMaker()
}
extension SafeDependencyResolver {
func registeredService() -> CoffeeMaker {
return resolve(CoffeeMaker.self)!
}
}
选项
- name
- 为服务定义一个名称。生成的方法将使用该名称。
- scope
- 参见 Swinject 对象作用域
- type
- 定义阶级注册的类型。当您想对协议进行解析时使用它。
/// sourcery:inject: scope = "weak", type = "Maker", name = "Arabica"
class CoffeeMaker: Maker { }
inject
(init)
为注入注册特定的 init。如果没有提供注解,则使用找到的第一个。
注意:类仍然需要
inject
注解。
// sourcery: inject
class CoffeeMaker {
init(heater: Heater) { }
// sourcery: inject
convenience init() {
self.init(heater: CoffeHeater())
}
}
生成的代码
container.register(CoffeeMaker.self) {
return CoffeeMaker()
}
extension SafeDependencyResolver {
func registeredService() -> CoffeeMaker {
return resolve(CoffeeMaker.self)!
}
}
inject
(attribute)
在 init 之后注入属性。属性需要被标记为可选 (?
或 !
)。
注意:类仍然需要
inject
注解。
// sourcery: inject
class CoffeeMaker {
/// sourcery: inject
var heater: Heater!
init() { }
}
生成的代码
container.register(CoffeeMaker.self) {
return CoffeeMaker()
}
.initCompleted { service, resolver in
service.heater = resolver.registeredService()
}
provider
使用自定义函数来注册您的依赖项。这与手动实现 container.register
同时保持安全性相同。请注意,提供的方法 必须 在instantiate
中调用。
注意:如果您正在提供第三方库(例如来自 Cocoapods 的库),则需要将那些导入传递给 AnnotationInject,使用
args.imports MyLib,MyLib2,...
命令行参数。
class CoffeeMaker {
init(heater: Heater) { }
}
// sourcery: provider
class AppProvider {
static func instantiate(resolver: SafeDependencyResolver) -> CoffeeMaker {
return CoffeeMaker(heater: CoffeHeater())
}
}
生成的代码
container.register(CoffeeMaker, factory: AppProvider.instantiate(resolver:))
extension SafeDependencyResolver {
func registeredService() -> CoffeeMaker {
return resolve(CoffeeMaker.self)!
}
}
provided
(自 0.5.0 版本后不再需要)
将参数声明为参数,用于在解析方法中定义。在 init 和 provider 方法上工作。
注意事项
生成的代码由于缺少导入而无法编译
设置 --args imports=<MyLib1> -args imports=<MyLib2>>
,以便生成的代码包含第三方库。
在生成的代码中,Foundation 类型(URLSession、NSNotificationCenter 等)为空(.self)
Sourcery 目前无法找到这些类型。因此,它们被视为不存在。解决方案:在 Provider 内部定义周围类型并为其提供 Foundation 类型。
构建阶段失败,没有错误报告
这可能是由于 Sourcery 与 Xcode 11.4 存在不兼容。解决方案:使用 Homebrew 安装 Sourcery 然后将 SOURCERY_BINPATH=sourcery
添加到构建步骤中的环境变量。
Pods/Sourcery/bin/Sourcery.app/Contents/MacOS/Sourcery:找不到文件或目录
您可能正在将 Sourcery 作为 Cocoapods 依赖项使用,但遗憾的是它并不总是工作得很好。解决方案:使用 Homebrew 安装 Sourcery,然后将 SOURCERY_BINPATH=sourcery
添加到构建步骤中的环境变量。
许可协议
本项目采用 MIT 许可证发布。请参阅 LICENSE 文件以获取详细信息。