Container is a lightweight dependency injection framework for Swift.


Container is available through Swift Package Manager.

Swift Package Manager

Basic Usage

First, register a service to a Container, there are two ways to register your dependencies, directly to the Container and through the expansion of DependencyContainer

let container = DependencyContainer.shared

In a real project, it is recommended to use the second approach. You can create a separate file with this extension

struct DependenciesConfigurator {
    static func configure() {
        let container = DependencyContainer.shared
        // Setup Modules
        // Setup Services
        container.apply(AppConfigService() as AppConfigServiceProtocol)
        container.apply(EnvironmentService() as EnvironmentServiceProtocol)
        // Appearance
        container.apply(, label: .redColor)
        // Date Formatter
        container.apply(DateFormatterPool() as DateFormatterPoolProtocol)

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool {
        // Setup Dependency

        return true

Then get an instance of a service from the container.

let service = container.resolve(Service.self, scope: .unowned)

In a real project, it is recommended to use PropertyWrapers

class ViewModel {
    @Container(scope: .strong) var config: AppConfigServiceProtocol
    func setup() {
        let token = config.obtain(for: .token)


You can specify the scope for your dependencies, .weak .strong and .unowned

.weak scope is used by default

@Container var service: ServiceProtocol // .weak scope is used

How it’s work

  • weak

Keeps the object in memory while at least one object refers to it

  • strong

An analogue of Singletone, after creating the object, it always remains in memory even if no one refers to it

  • unowned

The object is not stored in memory and each time create a new object


For the same types, you can specify Label For exemple:

container.apply(, label: .redColor)
container.apply(, label: .greenColor)
container.apply(, label: .orangeColor)

In order to create your own Label, you need to extension the structure of Containerlabel

extension ContainerLabel {
    static let redColor = ContainerLabel(value: "redColor")
    static let greenColor = ContainerLabel(value: "greenColor")
    static let orangeColor = ContainerLabel(value: "orangeColor")


Container also support Assembly for assembly your Modules

First, register a Assembly to a Container

extension DependencyContainer {
    func configureAssembly(container: AssemblyApplier) {
    func configureDependency(container: DependencyApplier) {
        container.apply(AppConfigService() as AppConfigServiceProtocol)

Then implement the MainAssembly class

typealias MainModule = Module<MainModuleInput, MainModuleOutput>

class MainAssembly: Assembly {
    @Container(scope: .strong) var config: AppConfigServiceProtocol
    func build(coordinator: MainCoordinator) -> MainModule {
        // View
        let view = MainViewController()
        // Router
        let router = MainRouter(coordinator: coordinator)
        // ViewModel
        let viewModel = MainViewModel(router: router, config: config)
        // Configure
        viewModel.view = view
        view.output = viewModel
        return Module(view: view, input: viewModel, output: viewModel)

How to usage

class MainCoordinator: BaseCoordinator {
    // MARK: - Dependencies
    @AssemblyContainer var mainAssembly: MainAssembly
    override func start() {
        let module = self)

Example Apps

Coming soon


MIT license. See the LICENSE file for details.


View Github