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
Copy file name to clipboardExpand all lines: README.md
+144-1Lines changed: 144 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -12,7 +12,8 @@ The Swift Dependency Injection Container is a lightweight and flexible library d
12
12
- Property wrappers for convenient dependency injection.
13
13
- Dynamic module registration and management.
14
14
- Result builder syntax for declarative module registration.
15
-
- Debug utilities for module and injection key scanning.
15
+
- Debug-only scanners for discovering injection keys and auto modules.
16
+
- Automatic module registration for debug builds via `AutoModule` and `Container.autoRegisterModules()`.
16
17
17
18
## Requirements
18
19
@@ -73,6 +74,148 @@ struct Cat: Meow {
73
74
}
74
75
```
75
76
77
+
# Dependency Injection Container
78
+
79
+
[English](README.md) | [한국어](README-ko.md)
80
+
81
+
## Overview
82
+
83
+
The Swift Dependency Injection Container is a lightweight and flexible library designed to facilitate dependency management in Swift applications. It provides a structured and type-safe approach to resolve dependencies throughout your codebase, promoting code reusability, testability, and maintainability.
84
+
85
+
## Features
86
+
- Type-safe dependency resolution.
87
+
- Lazy instantiation of dependencies.
88
+
- Property wrappers for convenient dependency injection.
89
+
- Dynamic module registration and management.
90
+
- Result builder syntax for declarative module registration.
91
+
- Debug-only scanners for discovering injection keys and auto modules.
92
+
- Automatic module registration for debug builds via `AutoModule` and `Container.autoRegisterModules()`.
First, register a key and module pair to a `Container`, where the module has concreate type. `Key` has `protocol type`, and `concreate type` is inheriting `protocol type`
121
+
122
+
```swift
123
+
Container {
124
+
Module(AnimalKey.self) { Cat() }
125
+
}
126
+
.build()
127
+
```
128
+
129
+
Then get an instance from the container.
130
+
131
+
```swift
132
+
@Inject(AnimalKey.self)
133
+
var cat: Meow
134
+
cat.doSomething() // prints "Meow.."
135
+
// or
136
+
Container[AnimalKey.self].doSomething() // prints "Meow.."
137
+
```
138
+
139
+
Where definitions of the protocols and struct are
140
+
141
+
```swift
142
+
classAnimalKey: InjectionKey {
143
+
var type: Meow?
144
+
}
145
+
146
+
protocolMeow {
147
+
funcdoSomething()
148
+
}
149
+
150
+
structCat: Meow {
151
+
funcdoSomething() {
152
+
print("Meow..")
153
+
}
154
+
}
155
+
```
156
+
157
+
### Scanner and Automatic Module Registration
158
+
159
+
DIContainer includes debug-only scanners that discover injection keys and auto modules from the loaded app:
160
+
161
+
-`ModuleScanner` uses the Objective-C runtime to scan classes.
162
+
-`MachOLoader` scans Swift metadata from loaded Mach-O images.
163
+
-`Container.autoRegisterModules()` builds a container by converting scanned `AutoModule` implementation types into `Module` values.
164
+
165
+
The key and the implementation have different responsibilities:
166
+
167
+
- An `InjectionKey` defines the dependency contract. Its `Value` is usually a protocol or abstract type that callers depend on.
168
+
- An `AutoModule` implementation provides the concrete type. Its `ModuleKeyType` tells the scanner which key should be used for registration.
169
+
-`keyList` is useful for diagnostics, but automatic registration is driven by scanned `AutoModule` implementations and their `ModuleKeyType`.
170
+
171
+
In the example below, `FooServiceKey` exposes `FooService` as the resolvable type, and `FooServiceImpl` is the concrete implementation discovered by the scanner.
After scanning, DIContainer treats the implementation like this explicit registration:
192
+
193
+
```swift
194
+
Module(FooServiceKey.self) {
195
+
FooServiceImpl() as FooService
196
+
}
197
+
// or
198
+
Module(FooServiceImpl.self)
199
+
```
200
+
201
+
Then register all scanned modules in a debug composition root.
202
+
203
+
```swift
204
+
#if DEBUG
205
+
Container.autoRegisterModules()
206
+
#endif
207
+
```
208
+
209
+
You can also inspect scan results directly.
210
+
211
+
```swift
212
+
let keys =ModuleScanner().keyList
213
+
let modules =ModuleScanner().scanModuleList
214
+
Container(modules: modules).build()
215
+
```
216
+
217
+
Scanner APIs are compiled only under `#if DEBUG`. They are useful for diagnostics and demo/test registration, while production composition should remain explicit and covered by tests.
0 commit comments