DICE 0.9.1

DICE 0.9.1

Anton PaliakovAlexander Tereshkov 维护。



DICE 0.9.1

  • 作者:
  • Alexander Tereshkov

DICE

CI Status codecov Version License Platform

DICE 是一个轻量级的 Swift 框架,为 Swift 和 SwiftUI 项目的属性库提供基于属性的依赖注入。DICE 还提供通过容器的服务定位模式。通过属性包装器或通过 DI 容器轻松注入依赖项。DICE 支持不同的作用域(单例、懒加载弱引用、懒加载原型、懒加载对象图)。

系统要求

  • Swift 5.1
  • iOS 13.0

安装

DICE 可通过 CocoaPods 获取。要安装它,只需将以下行添加到 Podfile 中

pod 'DICE'

示例

要运行示例项目,首先克隆仓库,然后从 Example 目录运行 pod install

使用方法

通过DI容器注入

1. 添加导入

import DICE

2. 声明你的容器

let container = DIContainer()

3. 注册你的实例

container.register(DummyServiceType.self) { _ in
    return DummyService()
}

例如,DummyServiceType只是一个协议,而DummyService是一个实现。

protocol DummyServiceType {
    func test()
}

class DummyService: DummyServiceType {
    func test() {
        Swift.print("DummyService")
    }
}

4. 将容器传递给DICE

DICE.use(container)

5. 解析实例

使用DIContainer

import UIKit
import DICE

class ViewController: UIViewController {
    let container = DIContainer()
    // In real case you'll need to pass container in ViewController or another class and all the dependencies should have been already registered prior to using container
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        container.register(DummyServiceType.self, scope: .single) { _ in
            return DummyService()
        }
        
        DICE.use(container)
        
        let service: DummyServiceType = container.resolve()
        service.test()
        
        // It should print "DummyService" in Xcode console
        // If you get error here, so check previous steps or open an issue
    }
}

使用@Injected属性包装器

import UIKit
import DICE

class ViewController: UIViewController {
    @Injected var dummyService: DummyServiceType
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        dummyService.test()
        // It should print "DummyService" in Xcode console
        // If you get error here, so check previous steps or open an issue
    }
}

在SwiftUI中注入

EnvironmentObservableInjected

自动订阅并使视图在变化时自动无效化的动态视图属性包装器。

struct ContentView: View {
    @EnvironmentObservableInjected var viewModel: ContentViewModel

    var body: some View {
        HStack {
            Text(viewModel.title)
        }.onAppear { self.viewModel.startUpdatingTitle() }
    }
}

...

class ContentViewModel: ObservableObject {
    @Published private(set) var title: String = ""
    
    func startUpdatingTitle() {
        self.title = "Test"
    }
}

EnvironmentInjected

从环境容器注入对象的属性包装器。只读对象。通常用于不可变对象。

struct ContentView: View {
    @EnvironmentInjected var service: WebService

    var body: some View {
        HStack {
            Text("Waiting...")
        }.onAppear { self.service.auth() }
    }
}

高级用法

作用域

默认范围

默认范围为 DIScope.objectGraph。在注册对象时如果没有设置范围,所有已注册的对象都将使用默认范围。可以通过设置 DICE.Defaults.scope 来修改,例如

DICE.Defaults.scope = .single

支持的范围

  • DIScope.single

依赖项在每个容器中按单例创建。建议用于一旦注入到 DIContainer 就应实例化的单例。

  • DIScope.weak

依赖项会在每个容器中懒加载创建,但在依赖对象即将 deinited 时销毁。只有在第一次调用后对象才会实例化。

  • DIScope.prototype

依赖项实例每次都会懒加创建。对象仅在实际调用后第一个调用才会实例化。

  • DIScope.objectGraph

依赖项实例在每个对象图中固定懒加创建,对象也仅在实际调用后第一个调用才会实例化。

设置范围

您可以在注册对象时使用可选的 scope 参数来指定范围。如果没有传递范围,则使用默认范围 DIScope.Defaults.scope

container.register(InjectableServiceType.self, scope: .objectGraph) { _ in
    return InjectableService()
}

在注入时使用容器解析器

假设 InjectableService 需要在初始化器中接收 InternalServiceType 作为依赖项。

class InjectableService: InjectableServiceType {
    let internalService: InternalServiceType
    
    init(internalService: InternalServiceType) {
        self.internalService = internalService
    }
}
  1. 注册 InternalServiceType
container.register(InternalServiceType.self) { _ in
    return InternalService()
}
  1. 在注册 InjectableServiceType 并将其传递给 InjectableService 时,从容器中解析 InternalServiceType
container.register(InjectableServiceType.self) { container in
    let internalService: InternalServiceType = container.resolve()
    return InjectableService(internalService: internalService)
}

标记

在注册依赖时,您可以为一个对象分配一个标签。当您使用 DIContainer.resolve() 或属性包装器 InjectedEnvironmentObservableInjectedEnvironmentInjected 来解析依赖时,可以使用标签来注入匹配您传入标签的对象。

使用标签注册依赖

container.register(InternalServiceType.self, tag: "dependency1") { _ in
    return InternalService(test: "stringInternal")
}

使用标签解析依赖

假设我们想要注入类型为 InternalServiceType 且标签为 dependency1InternalService

  1. 使用 DIContainer.resolve() 进行解析
let service: InternalServiceType = container.resolve(tag: "dependency1")
  1. 使用属性包装器进行解析
@Injected("dependency1") var service: InternalServiceType

版本控制

版本号遵循 语义化版本控制 方式。

沟通与帮助

参与贡献

我们非常乐意接受来自社区的贡献,这就是我们把它开源的主要原因!

  1. 进行Fork([https://github.com/DICE-Swift/dice/fork)(https://github.com/DICE-Swift/dice/fork)
  2. 创建你的功能分支(git checkout -b feature/fooBar)
  3. 提交你的更改(git commit -am '添加一些fooBar')
  4. 推送到分支(git push origin feature/fooBar)
  5. 创建一个新的[https://github.com/DICE-Swift/dice/pulls](https://github.com/DICE-Swift/dice/pulls)pull请求

贡献者

维护者

贡献者

想成为第一个贡献者吗?请建议您通过贡献部分来改进。

许可证

DICE遵循MIT许可证。有关更多信息,请参阅LICENSE文件。