Skip to content

minsOne/DIContainer

Repository files navigation

Dependency Injection Container

English | 한국어

Overview

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.

Features

  • Type-safe dependency resolution.
  • Lazy instantiation of dependencies.
  • Property wrappers for convenient dependency injection.
  • Dynamic module registration and management.
  • Result builder syntax for declarative module registration.
  • Debug-only scanners for discovering injection keys and auto modules.
  • Automatic module registration for debug builds via AutoModule and Container.autoRegisterModules().

Requirements

  • Swift 5.9+

Installation

DIContainer is available Swift Package Manager.

Swift Package Manager

in Package.swift add the following:

dependencies: [
    .package(url: "https://github.com/minsOne/DIContainer.git", from: "1.0.0")
]

Usage

Basic Usage

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

Container {
    Module(AnimalKey.self) { Cat() }
}
.build()

Then get an instance from the container.

@Inject(AnimalKey.self)
var cat: Meow
cat.doSomething() // prints "Meow.."
// or
Container[AnimalKey.self].doSomething() // prints "Meow.."

Where definitions of the protocols and struct are

class AnimalKey: InjectionKey {
    var type: Meow?
}

protocol Meow {
    func doSomething()
}

struct Cat: Meow {
    func doSomething() {
        print("Meow..")
    }
}

Scanner and Automatic Module Registration

DIContainer includes debug-only scanners that discover injection keys and auto modules from the loaded app:

  • ModuleScanner uses the Objective-C runtime to scan classes.
  • MachOLoader scans Swift metadata from loaded Mach-O images.
  • Container.autoRegisterModules() builds a container by converting scanned AutoModule implementation types into Module values.

The key and the implementation have different responsibilities:

  • An InjectionKey defines the dependency contract. Its Value is usually a protocol or abstract type that callers depend on.
  • An AutoModule implementation provides the concrete type. Its ModuleKeyType tells the scanner which key should be used for registration.
  • keyList is useful for diagnostics, but automatic registration is driven by scanned AutoModule implementations and their ModuleKeyType.

In the example below, FooServiceKey exposes FooService as the resolvable type, and FooServiceImpl is the concrete implementation discovered by the scanner.

final class FooServiceKey: InjectionKey {
    typealias Value = FooService
}

protocol FooService {
    func doSomething()
}

final class FooServiceImpl: AutoModule, FooService {
    typealias ModuleKeyType = FooServiceKey

    func doSomething() {
        print("Foo")
    }
}

After scanning, DIContainer treats the implementation like this explicit registration:

Module(FooServiceKey.self) {
    FooServiceImpl() as FooService
}
// or
Module(FooServiceImpl.self)

Then register all scanned modules in a debug composition root.

#if DEBUG
Container.autoRegisterModules()
#endif

You can also inspect scan results directly.

let keys = ModuleScanner().keyList
let modules = ModuleScanner().scanModuleList
Container(modules: modules).build()

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.

Test

$ (cd MockData/Sources/MockData && for i in {1..20}; do cp MockClass.swift MockClass$i.swift; done)
$ swift test
$ swift test -Xswiftc -O

Contributing

Contributions to the Swift Dependency Injection Container are welcome. Here are ways you can contribute:

  • Reporting issues
  • Suggesting enhancements
  • Submitting pull requests with bug fixes or new features

Please ensure to follow the coding standards and write tests for new functionality.

License

This project is licensed under the MIT License.

Post

Credits

The DIContainer are inspired by:

About

DIContainer is lightweight dependency injection container framework for Swift

Topics

Resources

License

Stars

43 stars

Watchers

2 watching

Forks

Packages

 
 
 

Contributors

Languages