DIKit

Build Status

一个 Swift 的静态类型依赖注入器。

概述

DIKit 提供了表达依赖图的接口。一个名为 dikitgen 的代码生成器会查找这些接口的实现,并生成满足依赖图的代码。

DIKit 的主要组成部分是可注入类型和提供者方法,它们都用于声明类型的依赖关系。

可注入类型是指符合 Injectable 协议的类型。

public protocol Injectable {
    associatedtype Dependency
    init(dependency: Dependency)
}

Injectable 协议的遵循者必须具有关联类型 Dependency 作为结构体。 您将 Injectable 遵循者的依赖项声明为 Dependency 类型的存储属性。 例如,假设我们有 ProfileViewController 类,它的依赖项是 UserAPIClientDatabase。 以下示例代码说明了如何通过遵循 Injectable 协议来声明依赖项。

final class ProfileViewController: Injectable {
    struct Dependency {
        let user: User
        let apiClient: APIClient
        let database: Database
    }

    init(dependency: Dependency) {...}
}

提供者方法是 Resolver 协议继承者的方法,Resolver 协议是一个用于代码生成的标记协议。

public protocol Resolver {}

提供者方法声明了哪些非可注入类型可以被自动实例化。 在上面的示例中,APIClientDatabase 是非可注入类型,但在大多数情况下,它们可以用相同的方式提供。 在这种情况下,为 Resolver 协议的继承者中的类型定义提供者方法,以便自动提供这些类型的实例。

protocol AppResolver: Resolver {
    func provideAPIClient() -> APIClient
    func provideDatabase() -> Database
}

简而言之,目前的情况如下

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

mint install ishkawa/DIKit dikitgen

从源代码

git clone https://github.com/ishkawa/DIKit.git
cd DIKit
make install

然后,将 DIKit.framework 集成到您的项目中。 有一些选项可以安装 DIKit.framework。

(可选)将运行 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