A tiny dependency injection container for Swift. No third-party dependencies, works on iOS and macOS.
Licensed under MIT.
.package(url: "https://github.com/PedroAugusto01/DIKit", from: "1.0.0").product(name: "DIKit", package: "DIKit"),DIContainer maps a type to a factory closure. register stores the factory; resolve calls it (or returns the cached instance, for singletons):
let container = DIContainer()
container.register(Logging.self, scope: .singleton) { _ in ConsoleLogger() }
container.register(UserService.self) { resolver in
UserService(logger: resolver.resolve(Logging.self))
}
let service: UserService = container.resolve(UserService.self)scope: .transient(the default) builds a fresh instance on everyresolve.scope: .singletonbuilds the instance once, on firstresolve, and reuses it after that.register(_:instance:)registers an already-built value as a singleton directly.- Factories receive the container itself, so a service can resolve its own dependencies from it — nested resolution doesn't deadlock, since the container never holds its lock while running a factory.
resolve(_:)traps with a descriptive message if nothing was registered for that type — a missing registration is a wiring mistake, not something to recover from at runtime. UsetryResolve(_:)if you'd rather getnil.
For call sites that would rather not thread a container through every initializer:
final class ProfileViewModel {
@Injected private var userService: UserService
}By default it resolves from DIContainer.shared, the process-wide default container. Pass a different one (@Injected(container: myContainer)) when you're managing your own — most tests should.
swift run DIKitDemoswift test