依赖注入模式的一种实现。kvEnvironment 提供
对于任何平台都没有明确的限制。因此,假设 kvEnvironment 可以在任何 Swift 可用的平台上编译。
.package(url: "https://github.com/keyvariable/kvEnvironment.git", from: "0.5.1")
.product(name: "kvEnvironment", package: "kvEnvironment")
import kvEnvironment
extension KvEnvironmentScope {
#kvEnvironment { var someProperty: SomeType }
}
@KvEnvironment(\.someProperty) private var someProperty
以下示例展示了 C
依赖于 A
和 B
的情况
struct A { let a: Int }
struct B { let b: String }
extension KvEnvironmentScope {
#kvEnvironment {
var a: A?
var b: B = .init(b: "default")
}
}
struct C {
@KvEnvironment(\.a) private var a
@KvEnvironment(\.b) private var b
}
环境属性 a
被声明为可选类型。#kvEnvironment
宏为可选类型提供了隐式默认值 nil
。环境属性 b
被声明为不透明类型并且有一个默认值。因此,由于提供了默认值,C
可以在任何作用域的任何时刻被实例化。
如果一个环境属性在定义时没有默认值,那么它必须在其 getter 被调用之前显式地初始化。
有全局(KvEnvironmentScope.global
)和任务本地(KvEnvironmentScope.current
)作用域。可以创建独立或覆盖的作用域
// By default new scopes override global scope.
let aScope = KvEnvironmentScope {
$0.a = A(a: 1)
}
// Parent scope can be explicitly provided.
// So in `abScope` both `a` and `b` properties are overridden.
let abScope = KvEnvironmentScope(parent: aScope) {
$0.b = B(b: "custom")
}
以下是临时覆盖全局作用域的一种方式的示例
let c = C()
// Here dependencies are resolved in the global scope.
print(c)
// In block below current scope is changed to `abScope`.
abScope {
// Here dependencies are resolved in `abScope`.
print(c)
}
有几种方法可以为依赖引用提供显式的作用域
@Environment(\.a, scope: someScope) private var a
;$a.scope = someScope
;KvEnvironmentScope
的 replace(in:options:)
方法更改任意实例的所有作用域引用。struct E {
let id: String
@KvEnvironment(\.f) var f
}
struct F {
let id: String
@KvEnvironment(\.e) var e
}
extension KvEnvironmentScope {
#kvEnvironment {
var e: E
var f: F
}
}
struct G: CustomStringConvertible {
@KvEnvironment(\.e) private var e
@KvEnvironment(\.f) private var f
}
// Populating global scope with required values.
KvEnvironmentScope.global {
$0.e = E(id: "e1")
$0.f = F(id: "f1")
}
let g = G()
// e: "e1", f: "f1", e.f: "f1", f.e: "e1".
print(g)