一个 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