-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDependency.swift
106 lines (102 loc) · 3.48 KB
/
Dependency.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/// A property wrapper for accessing dependencies.
///
/// All dependencies are stored in ``DependencyValues`` and one uses this property wrapper to gain
/// access to a particular dependency. Typically it used to provide dependencies to features such as
/// an observable object:
///
/// ```swift
/// final class FeatureModel: ObservableObject {
/// @Dependency(\.apiClient) var apiClient
/// @Dependency(\.continuousClock) var clock
/// @Dependency(\.uuid) var uuid
///
/// // ...
/// }
/// ```
///
/// Or, if you are using [the Composable Architecture][tca]:
///
/// ```swift
/// struct Feature: ReducerProtocol {
/// @Dependency(\.apiClient) var apiClient
/// @Dependency(\.continuousClock) var clock
/// @Dependency(\.uuid) var uuid
///
/// // ...
/// }
/// ```
///
/// But it can be used in other situations too, such as a helper function:
///
/// ```swift
/// func sharedEffect() async throws -> Action {
/// @Dependency(\.apiClient) var apiClient
/// @Dependency(\.continuousClock) var clock
///
/// // ...
/// }
/// ```
///
/// > Warning: There are caveats to using `@Dependency` in this style, especially for applications
/// not built in the Composable Architecture or that are not structured around a "single point of
/// entry" concept. See the articles <doc:Lifetimes> and <doc:SingleEntryPointSystems> for more
/// information.
///
/// For the complete list of dependency values provided by the library, see the properties of the
/// ``DependencyValues`` structure.
///
/// [tca]: https://github.com/pointfreeco/swift-composable-architecture
@propertyWrapper
public struct Dependency<Value>: @unchecked Sendable, _HasInitialValues {
let initialValues: DependencyValues
// NB: Key paths do not conform to sendable and are instead diagnosed at the time of forming the
// literal.
private let keyPath: KeyPath<DependencyValues, Value>
private let file: StaticString
private let fileID: StaticString
private let line: UInt
/// Creates a dependency property to read the specified key path.
///
/// Don't call this initializer directly. Instead, declare a property with the `Dependency`
/// property wrapper, and provide the key path of the dependency value that the property should
/// reflect:
///
/// ```swift
/// final class FeatureModel: ObservableObject {
/// @Dependency(\.date) var date
///
/// // ...
/// }
/// ```
///
/// - Parameter keyPath: A key path to a specific resulting value.
public init(
_ keyPath: KeyPath<DependencyValues, Value>,
file: StaticString = #file,
fileID: StaticString = #fileID,
line: UInt = #line
) {
self.initialValues = DependencyValues._current
self.keyPath = keyPath
self.file = file
self.fileID = fileID
self.line = line
}
/// The current value of the dependency property.
public var wrappedValue: Value {
#if DEBUG
var currentDependency = DependencyValues.currentDependency
currentDependency.file = self.file
currentDependency.fileID = self.fileID
currentDependency.line = self.line
return DependencyValues.$currentDependency.withValue(currentDependency) {
self.initialValues.merging(DependencyValues._current)[keyPath: self.keyPath]
}
#else
return self.initialValues.merging(DependencyValues._current)[keyPath: self.keyPath]
#endif
}
}
protocol _HasInitialValues {
var initialValues: DependencyValues { get }
}