You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I used SwiftUI here for simplicity, Inject doesn't require anything but `Swift 5.7`.
44
+
extensionSomeView: Injectable {}
61
45
62
-
Now the first problem is preview, now it will need an actual `URL` and a network connection, which is not what we want.
46
+
structSomeView_Previews: PreviewProvider {
47
+
staticvar previews: some View {
48
+
SomeView()
49
+
.injecting(MockNetworking(), for: \.network)
50
+
}
51
+
}
52
+
```
63
53
64
-
To enable injection we need to tell the compiler that we use `URLSessionDownloader` as a default instance for the protocol `DownloaderInterface`:
54
+
With this convenient property wrapper `@Injected` you define a dependency requirement in a declarative way:
55
+
-`\.networking` is the `KeyPath` to the instance to be obtained at [`\DefaultValues.networking`. ](#default-values)
56
+
57
+
-`network` is the name of our injection point that we use to inject in preview `.injecting(MockNetworking(), for: \.network)`.
58
+
It behaves just like a normal variable would, with one exception, instead of providing an instance it provides a `Dependency<T>` wrapper, that has a computed property `.instance` to obtain an actual instance of type `T`.
65
59
66
-
```swift
67
-
importInject
60
+
-**MockNetworking** - A class that we use only in tests or previews, that might simulate the network.
68
61
69
-
extensionDefaultValues {
70
-
var imageDownloader: DownloaderInterface { URLSessionDownloader() }
71
-
}
72
-
```
62
+
- Note: *We have to mark our view with an empty protocol `Injectable` to enable the `injecting(_:_:)` function.*
73
63
74
-
We also can now refer to it with a `KeyPath``\DefaultValues.imageDownloader` which is very handy since we would need to replace it once if we changed from `URLSession` to something else.
64
+
**That's it, you are done with dependency injection without a need to know what exactly that is.**
75
65
76
-
That's all we need to use the instance in our view:
77
66
78
-
```swift
79
-
importInject
67
+
The only thing that is missing is to tell the compiler what are the default values for our `\.networking` and `\.parser` dependencies. And that's where `DefaultValues` come in handy.
80
68
81
-
structRemoteImage: View, Injectable {
82
-
@Injected(\.imageDownloader) var downloader
83
-
```
69
+
## Default Values
84
70
85
-
We have to mark our view as `Injectable` which is an empty protocolenabling the `injecting(_:_:)`function. And tell which instance we need, `\.imageDownloader`is a short syntax for `\.DefaultValues.imageDownloader`.
71
+
**Unlike other popular solutions Inject doesn't have a container** instead it provides you with a `DefaultValues` class to extend with computed properties.
86
72
87
-
Now in our preview, we can easily replace the production instance of the downloader with our mock that provides a static test image, error, and other cases we want to test.
73
+
**You never need to create an instance of this class**, all you need to do is to extend it with the variable of the type of the dependency it represents and return a default implementation for it:
If you noticed `networking` and `parser` are the names we referred to earlier.
90
+
91
+
## Dependency configuration
92
+
93
+
You might wonder, what is the lifespan of the instances provided? Do they stay in memory forever like singletons or they are destroyed when the object that has them `@Injected` is destroyed?
94
+
95
+
And what is the scope, are all instances for all classes the same, or each class will have a new instance for its `@Injected`?
96
+
97
+
The answer is, by default, all the instances are created for each `@Injected` and are destroyed once the object that holds `@Injected` is destroyed.
98
+
99
+
But you can change that with the `Scope` and `Lifespan`, default values would be:
105
100
106
-
By default, all the dependencies are **providing a new instance** (`.temporary`)
107
-
and **foreach injection point** (`.local`)
108
-
and deallocated once an injection point is deallocated.
109
101
```swift
110
-
@Injected(\.networking, .temporary, .local) var network
102
+
@Injected(\.networking, scope: .local, lifespan: .temporary) var network
111
103
```
112
104
113
-
But you can alter it with `.shared` ``Dependency/Scope`` to provide the same instance to all consumers with `.shared` ``Dependency/Scope`` preferred.
114
-
Also, you can configure a `.permanent` ``Lifespan`` to hold it until the termination of the app.
105
+
here are the possible values:
106
+
107
+
### Scope
108
+
109
+
-`.local` - new instance for each `@Injected`
110
+
-`.shared` - same instance for all `@Injected`
111
+
112
+
### Lifespan
113
+
114
+
-`.permanent` - instance stays till the app is deallocated.
115
+
-`.temporary` - instance deallocated when the **last**`@Injected` referencing it is deallocated.
116
+
117
+
## Why yet another DI framework?
118
+
119
+
This is the question I asked the most.
120
+
121
+
Here are some of the reasons to try *Inject* and decide for yourself:
122
+
123
+
- Thread safety using `@MainActor`
124
+
- Inject doesn't resolve instances using a container, it doesn't have a container in the first place. Which is a huge advantage over other popular DI solutions for which it is the biggest bottleneck.
125
+
- Compile-time check that all the instances provided, which removes a whole layer of errors.
126
+
- Inject's API operates simple concepts like instance, injection/replacement, scope, and lifespan.
127
+
- It's extremely modular, you one-line it anywhere you want.
128
+
129
+
There is much more than that, I will soon provide a couple of examples using inject in the app and in another library to showcase how powerful and flexible Inject is.
130
+
131
+
Meanwhile, it's a good candidate for you to try and make your dependency injection a breeze.
132
+
115
133
116
134
# Installation
117
135
@@ -123,19 +141,5 @@ Inject is designed for Swift 5. To depend on the Inject package, you need to dec
0 commit comments