Toledo - a dependency injection library for Swift that statically generates resolvers at compile-time.

Overview

Toledo

Swift Xcode MIT

Toledo is a dependency injection library for Swift that statically generates resolvers at compile-time.

Index

Features

  • once it compiles, it works
  • async and throwing dependencies
  • concurrency support
  • multiple containers (no singleton)
  • makes no assumption about your code
  • conformance can be provided in extensions
  • works great with SwiftUI for view model DI
  • simple installation process via SPM

Installation

Using Swift Package Manager:

dependencies: [
    .package(
        name: "Toledo",
        url: "https://github.com/valentinradu/Toledo.git",
        from: "0.0.1"
    )
],
targets: [
    .target(
        name: "MyTarget",
        dependencies: ["Toledo"],
        plugins: [
            .plugin(name: "ToledoPlugin", package: "Toledo")
        ]
    )
]

Notice the plugin. It should be applied to all targets that use the library.

Usage

Toledo has 3 types of dependencies: regular, throwing and async throwing. Each has its own protocol that needs to be implemented for a type to be available in the dependency container. For example the conformance for a final class IdentityModel to AsyncThrowingDependency would look like this:

extension IdentityModel: AsyncThrowingDependency {
    public convenience init(with container: SharedContainer) async throws {
        await self.init(profile: try await container.profile(),
                        settings: container.settings())
    }
}

At compile time, Toledo will look for types conforming to Dependency, ThrowingDependency or AsyncThrowingDependency and will store shared instances of each on SharedContainer.

This means that the IdentityModel above will be available everywhere as try await container.identityModel() as long as you have a reference to the container. Notice how an async throwing dependency requires try await to resolve. If IdentityModel would have been a regular dependency, container.identityModel() would have been enough.

Shared instances vs new instances

Calling container.identityModel() always returns the same instance. If you wish to create a new instance within a given container, use the init(with:) directly:

let newInstance = IdentityModel(with: container)

Providing overrides

If you wish to provide alternative values for some of your dependencies (i.e. for testing) you can do so by setting the SharedContainer provider:

var container = SharedContainer()
container.profile = { MockedProfile() }
let mockedInstance = try await container.identityModel()

Concurrency

Toledo uses Swift's concurrency model to guarantee that shared instances are never instantiated more than once per container.

Limitations

For this initial version, init(with:) dependency conformance has to be public. This will likely change in the future.

License

MIT License

You might also like...
Kraken - Simple Dependency Injection container for Swift. Use protocols to resolve dependencies with easy-to-use syntax!
Kraken - Simple Dependency Injection container for Swift. Use protocols to resolve dependencies with easy-to-use syntax!

Kraken Photo courtesy of www.krakenstudios.blogspot.com Introduction Kraken is a simple Dependency Injection Container. It's aimed to be as simple as

ViperServices - Simple dependency injection container for services written for iOS in swift supporting boot order

ViperServices Introduction ViperServices is dependency injection container for iOS applications written in Swift. It is more lightweight and simple in

CarbonGraph - A Swift dependency injection / lookup framework for iOS

CarbonGraph is a Swift dependency injection / lookup framework for iOS. You can

A new approach to Container-Based Dependency Injection for Swift and SwiftUI.
A new approach to Container-Based Dependency Injection for Swift and SwiftUI.

A new approach to Container-Based Dependency Injection for Swift and SwiftUI. Why do something new? Resolver was my first Dependency Injection system.

Container is a lightweight dependency injection framework for Swift.
Container is a lightweight dependency injection framework for Swift.

Container Container is a lightweight dependency injection framework for Swift. Installation is available in the Swift Package Manager. Swift Package M

Effortless modular dependency injection for Swift.

Inject Effortless modular dependency injection for Swift. Sometimes during the app development process we need to replace instances of classes or acto

Corridor  A Coreader-like Dependency Injection ╬╝Framework
Corridor A Coreader-like Dependency Injection ╬╝Framework

Corridor A Coreader-like Dependency Injection ╬╝Framework Table of Contents Why | Examples | Usage | Installation | Credits & License | Why In order to

Deli is an easy-to-use Dependency Injection Container that creates DI containers
Deli is an easy-to-use Dependency Injection Container that creates DI containers

Deli is an easy-to-use Dependency Injection Container that creates DI containers with all required registrations and corresponding factories.

Dip is a simple Dependency Injection Container.

Dip is a simple Dependency Injection Container. It's aimed to be as simple as possible yet p

Comments
  • Investigate if there's a way to avoid `@MainActor` cascade

    Investigate if there's a way to avoid `@MainActor` cascade

    Right now the library forces the consumers to mark all points of contact as @MainActor. While this works, it's not ideal. Investigate if there's a way to prevent it and if the resulting trade-offs (which most likely will mean all resolvers will become async) are worth it.

    enhancement 
    opened by valentinradu 1
  • So... some problems.

    So... some problems.

    Probably missing something obvious, but I tried adding this to a project using SPM in Xcode and it only presented with an option to add the main library and not the plugin without which nothing will work.

    Since I can't get it fully working yet I'm not positive on this but do you have to define a class, then the class dependency, and THEN build the project such that said dependency now exists on the container. And then, and only then, can the reference on the container now be referenced in the code?

    Also appears to suffer from the MainActor cascade. Once you marked the entire container class as requiring MainActor then the dependent classes needed to be marked that way, and so on until you can't even create a SharedContainer() unless you too are within a MainActor.

    Also has a bit of a problem with adding dependency conformance via extensions as you can't provide the needed initializer unless your class is marked final. Ran into that issue myself awhile back playing with a successor to Resolver.

    opened by hmlongco 1
Releases(v1.1.0)
Owner
Valentin Radu
Valentin Radu
Injection - Dependency injection using property wrappers

Dependency injection using property wrappers. Registering types: // injecting a

Alejandro Ramirez 3 Mar 14, 2022
Tranquillity is a lightweight but powerful dependency injection library for swift.

DITranquillity Tranquillity is a lightweight but powerful dependency injection library for swift. The name "Tranquillity" laid the foundation in the b

Ivlev Alexander 393 Dec 24, 2022
DIContainer Swift is an ultra-light dependency injection container made to help developers to handle dependencies easily. It works with Swift 5.1 or above.

?? DIContainer Swift It is an ultra-light dependency injection container made to help developers to handle dependencies easily. We know that handle wi

Victor Carvalho Tavernari 10 Nov 23, 2022
Pilgrim - Dependency injection for Swift (iOS, OSX, Linux). Strongly typed, pure Swift successor to Typhoon.

pilgrim.ph Pilgrim is a dependency injection library for Swift with the following features: Minimal runtime-only library that works with pure Swift (s

AppsQuick.ly 60 Oct 24, 2022
Injector - A Swift package for simple dependency injection that also supports Swift UI previews

A Swift package for simple dependency injection that also supports Swift UI prev

null 6 Aug 9, 2022
Cleanse is a dependency injection framework for Swift.

Cleanse - Swift Dependency Injection Cleanse is a dependency injection framework for Swift. It is designed from the ground-up with developer experienc

Square 1.7k Dec 16, 2022
DIKit Dependency Injection Framework for Swift, inspired by KOIN.

DIKit Dependency Injection Framework for Swift, inspired by KOIN. Basically an implementation of service-locator pattern, living within the applicatio

null 95 Dec 22, 2022
Swinject is a lightweight dependency injection framework for Swift.

Swinject Swinject is a lightweight dependency injection framework for Swift. Dependency injection (DI) is a software design pattern that implements In

null 5.6k Dec 31, 2022
Dependency Injection framework for Swift (iOS/macOS/Linux)

Declarative, easy-to-use and safe Dependency Injection framework for Swift (iOS/macOS/Linux) Features Dependency declaration via property wrappers or

Scribd 684 Dec 12, 2022
Swift Ultralight Dependency Injection / Service Locator framework

Swift Ultralight Dependency Injection / Service Locator framework

Michael Long 1.9k Jan 6, 2023