一个 Swift 的静态类型依赖注入器。
DIKit 提供了表达依赖图的接口。一个名为 dikitgen 的代码生成器会查找这些接口的实现,并生成满足依赖图的代码。
DIKit 的主要组成部分是可注入类型和提供者方法,它们都用于声明类型的依赖关系。
可注入类型是指符合 Injectable 协议的类型。
public protocol Injectable {
associatedtype Dependency
init(dependency: Dependency)
}
Injectable 协议的遵循者必须具有关联类型 Dependency 作为结构体。 您将 Injectable 遵循者的依赖项声明为 Dependency 类型的存储属性。 例如,假设我们有 ProfileViewController 类,它的依赖项是 User、APIClient 和 Database。 以下示例代码说明了如何通过遵循 Injectable 协议来声明依赖项。
final class ProfileViewController: Injectable {
struct Dependency {
let user: User
let apiClient: APIClient
let database: Database
}
init(dependency: Dependency) {...}
}
提供者方法是 Resolver 协议继承者的方法,Resolver 协议是一个用于代码生成的标记协议。
public protocol Resolver {}
提供者方法声明了哪些非可注入类型可以被自动实例化。 在上面的示例中,APIClient 和 Database 是非可注入类型,但在大多数情况下,它们可以用相同的方式提供。 在这种情况下,为 Resolver 协议的继承者中的类型定义提供者方法,以便自动提供这些类型的实例。
protocol AppResolver: Resolver {
func provideAPIClient() -> APIClient
func provideDatabase() -> Database
}
简而言之,目前的情况如下
ProfileViewController 的依赖项是 User、APIClient 和 Database。APIClient 和 Database 的实例会自动提供。User 的实例才能实例化 ProfileViewController。dikitgen 为这些声明生成以下代码
extension AppResolver {
func resolveAPIClient() -> APIClient {
return provideAPIClient()
}
func resolveDatabase() -> Database {
return provideDatabase()
}
func resolveViewController(user: User) -> ProfileViewController {
let apiClient = resolveAPIClient()
let database = resolveDatabase()
return ProfileViewController(dependency: .init(user: User, apiClient: apiClient, database: Database))
}
}
要使用生成的代码,您必须实现 AppResolver 的具体类型。
final class AppResolverImpl: AppResolver {
let apiClient: APIClient = ...
let database: Database = ...
func provideAPIClient() {
return apiClient
}
func provideDatabase() {
return database
}
}
由于 AppResolver 是一个协议,因此所有提供者方法的实现都会在编译时进行检查。 如果您想为单元测试创建 AppResolver 的模拟版本,请定义 AppResolver 的另一个具体类型。 它可以像 AppResolverImpl 一样使用。
现在,您可以像下面这样实例化 ProfileViewController
let appResolver = AppResolverImpl()
let user: User = ...
let viewController = appResolver.resolveViewController(user: user)
首先安装代码生成器 dikitgen。
mint install ishkawa/DIKit dikitgen
git clone https://github.com/ishkawa/DIKit.git
cd DIKit
make install
然后,将 DIKit.framework 集成到您的项目中。 有一些选项可以安装 DIKit.framework。
DIKit.xcodeproj 添加到您的项目中。github "ishkawa/DIKIt" 并运行 carthage update。(可选)将运行 dikitgen 的 shell 脚本插入到构建阶段的早期部分。
if which dikitgen >/dev/null; then
dikitgen ${SRCROOT}/YOUR_PROJECT > ${SRCROOT}/YOUR_PROJECT/AppResolver.generated.swift
else
echo "warning: dikitgen not installed, download from https://github.com/ishkawa/DIKit"
fi