Swift 库,允许你通过创建一个包含所有依赖项的容器,在你的项目中使用依赖注入模式。
最推荐的创建容器的方式是使用程序集(Assemblies)。程序集是遵循 Assembly
协议的类,负责在容器中注册依赖项。
Container(assemblies: [
FoundationAssembly(),
APIAssembli(),
DataBaseAssembly(),
ThemeAssembly()
])
如果你想在 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)
container
- 创建一个单例实例并将其存储在容器中(类似于单例模式)weak
- 解析弱引用,如果它已经被释放,它将再次被解析transient
- 每次解析新的实例,永远不要将其存储在容器中你可以使用不同的名称注册同一类型的多个实例,并通过名称解析它们。
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
在一个类中实现不同协议的多个实现
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
}