https://github.com/divadretlaw/swiftui-dependencies
💉 SwiftUI-Environment based dependency injection
https://github.com/divadretlaw/swiftui-dependencies
dependency-injection environment swift swiftui
Last synced: 2 months ago
JSON representation
💉 SwiftUI-Environment based dependency injection
- Host: GitHub
- URL: https://github.com/divadretlaw/swiftui-dependencies
- Owner: divadretlaw
- License: apache-2.0
- Created: 2023-09-30T14:46:49.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-02-22T16:32:07.000Z (4 months ago)
- Last Synced: 2025-03-22T22:02:55.398Z (3 months ago)
- Topics: dependency-injection, environment, swift, swiftui
- Language: Swift
- Homepage:
- Size: 149 KB
- Stars: 1
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# SwiftUI Dependencies
SwiftUI-Environment based dependency injection
## Usage
First you create your dependencies, by creating `DependencyKey`s for them and adding them to `DependencyValues`, similar to declaring SwiftUI-Environment values.
But additionally to a `defaultValue`, you also provide a `previewValue` (automatically used in SwiftUI Previews) and `testingValue` (automatically used in Unit-Tests).
After you can access the dependencies in ViewModels and Views.
### Setup```swift
private struct MyDependencyKey: DependencyKey {
static var defaultValue: String {
"Default"
}
static var previewValue: String {
"Preview"
}
static var testingValue: String {
"Testing"
}
}extension DependencyValues {
var myDependency: String {
get { self[MyDependencyKey.self] }
set { self[MyDependencyKey.self] = newValue }
}
}
```You can always provide a custom value for views. The value will be propagated through the view hiearachy.
```swift
ContentView()
.dependency(\.myDependency, "New Value")
```### Usage in a `ObservableObject`
Instead of conforming to `ObservableObject` the view model should conform to `ObservableDependencyObject`. The `DependencyValues` of the current context will be provided in the required initializer.
```swift
final class ViewModel: ObservableDependencyObject {
required init(dependencies: DependencyValues) {
// Access the dependencies needed for this ViewModel
}
}struct ContentView: View {
@DependencyObject private var viewModel: ViewModel
var body: some View {
...
}
}
```In case you need a custom initializer for the view model, you can initialize the view model with dependencies like this:
```swift
final class ViewModel: ObservableDependencyObject {
let customProperty: String
required init(customProperty: String, dependencies: DependencyValues) {
self.customProperty = customProperty
// Access the dependencies needed for this ViewModel
}
}struct ContentView: View {
@DependencyObject private var viewModel: ViewModel
init() {
_viewModel = DependencyObject { dependencies in
ViewModel(customProperty: "Custom", dependencies: dependencies)
}
}
var body: some View {
...
}
}
```### Usage with `Obervable`
The model should conform to `ObservableDependency` and instead of annotating your model with `State` in the view, the model should be annotated with `DependencyState`. The `DependencyValues` of the current context will be provided in the required initializer.
```swift
@Observable
final class Model: ObservableDependency {
required init(dependencies: DependencyValues) {
// Access the dependencies needed for this ViewModel
}
}struct ContentView: View {
@DependencyState private var model: Model
var body: some View {
...
}
}
```### Usage in a View
You can access dependencies directly in views by using the `Dependency` annotation.
```swift
struct ContentView: View {
@Dependency(\.myDependency) private var myDependency
var body: some View {
Text(myDependency)
}
}
```### Demo
See the [demo project](Demo/Demo.xcodeproj) for some example implementations
## License
See [LICENSE](LICENSE)