DIKit - 依赖注入工具包

CI

Swift 库,允许你通过创建一个包含所有依赖项的容器,在你的项目中使用依赖注入模式。

创建容器

最推荐的创建容器的方式是使用程序集(Assemblies)。程序集是遵循 Assembly 协议的类,负责在容器中注册依赖项。

Container(assemblies: [
    FoundationAssembly(),
    APIAssembli(),
    DataBaseAssembly(),
    ThemeAssembly()
])

SwiftUI

如果你想在 SwiftUI 中使用 DIKit,你可以在 App 结构体中像这样创建一个容器

@main
struct MyApp: App {
    let container = Container(assemblies: [...])

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(container.toObservable())
        }
    }
}

// somewhere in the code
struct ContentView: View {
    @DIObservedObject var api: API
    
    var body: some View {
        Button("Make request") {
            api.request()
        }
    }
}

共享容器

如果你想在属性包装器 (InjectLazy, InjectProvider...) 中使用容器,你可以像这样创建一个共享容器

let container = Container(assemblies: [...])
container.makeShared()  // <-- make container shared

// somewhere in the code
final class SomeManager {
    @InjectLazy var api: API
    
    func makeRequest() {
        api.request()
    }
}

创建程序集

最基本的程序集应该像这样

final class ApplicationAssembly: Assembly {
    // list of assemblies that this assembly depends on
    var dependencies: [Assembly] { 
        return [
            AnalyticsAssembly(),
            RouterAssembly(),
            StoragesAssembly(),
            ThemeAssembly(),
            UIComponentsAssembly()
        ]
    }

    func assemble(with registrator: Registrator) {
        registrator.register(UserDefaults.self) {
            return UserDefaults.standard
        }

        registrator.register(NotificationCenter.self) {
            return NotificationCenter.default
        }

        registrator.register(UIApplication.self, options: .transient) {
            return UIApplication.shared
        }

        registrator.register(BuildMode.self, entity: BuildMode.init)
        
        registrator.register(UserManager.self, options: .container, entity: UserManager.init)
    }
}

如何解析依赖项

在任何可以访问容器的地方,你可以像这样解析依赖项

let api: API = container.resolve()
let dataBase: DataBase = container.resolve()

或者如果容器是共享的,你可以使用

@InjectLazy var api: API
@InjectProvider var dataBase: DataBase

的 SwiftUI

@DIObservedObject var api: API
@DIStateObject var viewState: ReCreatedState
@DIProvider var dataBase: DataBase

注册

最基本的注册看起来像这样

registrator.register(BuildMode.self, entity: BuildMode.init)

选项

'Named' 选项

你可以使用不同的名称注册同一类型的多个实例,并通过名称解析它们。

registrator.register(Theme.self, name: "light") {
    return LightTheme()
}

registrator.register(Theme.self, name: "dark") {
    return DarkTheme()
}

并像这样解析它

let lightTheme: Theme = container.resolve(name: "light")
let darkTheme: Theme = container.resolve(name: "dark")

@InjectLazy(named: "light") var lightTheme: Theme
@InjectLazy(named: "dark") var darkTheme: Theme

'.implements'

在一个类中实现不同协议的多个实现

registrator.register(UserDefaults.self) {
    return UserDefaults.standard
}
.implements(DefaultsStorage.self)

参数

你可以将参数传递给注册代码块

当你不知道参数的索引,但你确信参数中只有一种类型时

registrator.register(BlaBla.self, options: .transient) { _, args in
    return BlaBla(name: args.first()) <-- by type
}

当你知道参数的索引时

registrator.register(BlaBla.self, options: .transient) { _, args in
    return BlaBla(name: args[1]) <-- by index
}