All Projects → Swinject → Swinjectautoregistration

Swinject / Swinjectautoregistration

Licence: mit
Swinject extension to automatically register your services

Programming Languages

swift
15916 projects

Projects that are alternatives of or similar to Swinjectautoregistration

Di
PSR-11 compatible DI container and injector
Stars: ✭ 141 (-14.02%)
Mutual labels:  dependency-injection
Dingo
🐺 Easy, fast and type-safe dependency injection for Go.
Stars: ✭ 154 (-6.1%)
Mutual labels:  dependency-injection
Upcomingmovies
Movies app written in Swift 5 using the TMDb API and demonstrating Clean Architecture, Dependency Injection, MVVM and Coordinators.
Stars: ✭ 160 (-2.44%)
Mutual labels:  dependency-injection
Sactive Web
🚀 A dependency injection web framework for Node.js.
Stars: ✭ 143 (-12.8%)
Mutual labels:  dependency-injection
Dig
A reflection based dependency injection toolkit for Go.
Stars: ✭ 2,255 (+1275%)
Mutual labels:  dependency-injection
Fx
A dependency injection based application framework for Go.
Stars: ✭ 2,383 (+1353.05%)
Mutual labels:  dependency-injection
Autofac.annotation
Autofac extras library for component registration via attributes 用注解来load autofac 摆脱代码或者xml配置和java的spring的注解注入一样的体验
Stars: ✭ 140 (-14.63%)
Mutual labels:  dependency-injection
Mandarinets
Mandarine.TS is a typescript, decorator-driven framework that allows you to create server-side applications. Mandarine.TS provides a range of built-in solutions such as Dependency Injection, Components, ORM and more. Under its umbrella, Mandarine.TS has 4 modules: Core, Data, Security and MVC, these modules will offer you the requirements to build a Mandarine-powered application.
Stars: ✭ 161 (-1.83%)
Mutual labels:  dependency-injection
Package Builder
[READ-ONLY] Speed up your package DI containers integration and console apps to Symfony and Nette
Stars: ✭ 152 (-7.32%)
Mutual labels:  dependency-injection
Android Clean Architecture
Showcasing a Clean Architecture approach from our Android applications framework!
Stars: ✭ 160 (-2.44%)
Mutual labels:  dependency-injection
Dagger2
Kotlin Dagger2 example project
Stars: ✭ 145 (-11.59%)
Mutual labels:  dependency-injection
Hiboot
hiboot is a high performance web and cli application framework with dependency injection support
Stars: ✭ 150 (-8.54%)
Mutual labels:  dependency-injection
Container
A lightweight yet powerful IoC container for Go projects
Stars: ✭ 160 (-2.44%)
Mutual labels:  dependency-injection
Fluentvalidation.blazor
Fluent Validation-powered Blazor component for validating standard <EditForm> 🌌 ✅
Stars: ✭ 140 (-14.63%)
Mutual labels:  dependency-injection
Flama
🔥 Fire up your API with this flamethrower
Stars: ✭ 161 (-1.83%)
Mutual labels:  dependency-injection
Node Dependency Injection
The NodeDependencyInjection component allows you to standarize and centralize the way objects are constructed in your application.
Stars: ✭ 140 (-14.63%)
Mutual labels:  dependency-injection
Iquephoto
Android Image Editor Application.
Stars: ✭ 156 (-4.88%)
Mutual labels:  dependency-injection
Qframework
Unity3D System Design Architecture
Stars: ✭ 2,326 (+1318.29%)
Mutual labels:  dependency-injection
Kapsule
Minimalist dependency injection library for Kotlin.
Stars: ✭ 162 (-1.22%)
Mutual labels:  dependency-injection
Awilix
Extremely powerful Inversion of Control (IoC) container for Node.JS
Stars: ✭ 2,269 (+1283.54%)
Mutual labels:  dependency-injection

SwinjectAutoregistration

Build Status Carthage compatible CocoaPods Version License Platform Swift Version

SwinjectAutoregistration is an extension of Swinject that allows to automatically register your services and greatly reduce the amount of boilerplate code.

Requirements

  • iOS 8.0+ / Mac OS X 10.10+ / tvOS 9.0+
  • Xcode 8+

Installation

Swinject is available through Carthage or CocoaPods.

Carthage

To install Swinject with Carthage, add the following line to your Cartfile.

github "Swinject/Swinject" "2.7.0"
github "Swinject/SwinjectAutoregistration" "2.7.0"

Then run carthage update --no-use-binaries command or just carthage update. For details of the installation and usage of Carthage, visit its project page.

CocoaPods

To install Swinject with CocoaPods, add the following lines to your Podfile.

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0' # or platform :osx, '10.10' if your target is OS X.
use_frameworks!

pod 'Swinject', '2.7.0'
pod 'SwinjectAutoregistration', '2.7.0'

Then run pod install command. For details of the installation and usage of CocoaPods, visit its official website.

Registration

Here is a simple example to auto-register a pet owner

let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") } // Regular register method
container.autoregister(Person.self, initializer: PetOwner.init) // Autoregistration

where PetOwner looks like this:

class PetOwner: Person {
    let pet: Animal

    init(pet: Animal) {
        self.pet = pet
    }
}

The autoregister function is given the PetOwner initializer init(pet:Animal). From its signature Swinject knows that it needs a dependency Animal and resolves it from the container. Nothing else is needed.

Autoregistration becomes especially useful when used to register services with many dependencies. Compare autoregistration code:

container.autoregister(MyService.self, initializer: MyService.init)

with equivalent code in pure Swinject:

container.register(MyService.self) { r in 
	MyService(dependencyA: r.resolve(DependencyA.self)!, dependencyB: r.resolve(DependencyB.self)!, dependencyC: r.resolve(DependencyC.self)!, dependencyD: r.resolve(DependencyD.self)!)
}

Another advantage is that if you add more dependencies during the development the registration code doesn't have to be rewritten.

Registration with name

Service can be also given name - same as with the regular register method.

container.autoregister(Person.self, name: "johnny", initializer: PetOwner.init)

Arguments

You can also use auto-registration for services with dynamic arguments. Pet owner whose name needs to be passed as argument is defined like this:

class PetOwner: Person {
    let name: String
    let pet: Animal

    init(name: String, pet: Animal) {
        self.name = name
        self.pet = pet
    }
}

And registered like this

container.autoregister(Person.self, argument: String.self, initializer: PetOwner.init)

Swinject will register Person with the argument of type String. When container.resolve(Person.self, argument: "Michael") is called Swinject won't try to resolve String as dependency but instead pass "Michael" as the name.

To also pass pet as argument you can call

container.autoregister(Person.self, arguments: String.self, Animal.self, initializer: PetOwner.init)
//or
container.autoregister(Person.self, arguments: Animal.self, String.self, initializer: PetOwner.init)

The order of the arguments listed is interchangeable. The auto-registration can't be used with more arguments and/or dependencies of the same type.

What kind of sorcery is this?

Wondering how does that work? Generics are heavily leveraged for the auto-registration. For registering service with two dependencies something similar to a following function is used:

public func autoregister<Service, A, B>(_ service: Service.Type, initializer: (A, B) -> Service) -> ServiceEntry<Service> {
   return self.register(service.self, factory: { r in 
       return initializer(r.resolve(A.self)!, r.resolve(B.self)!)
   } as (ResolverType) -> Service)
}

The initializer is a function like any other. By passing it as a parameter its dependencies can be inferred as (A, B) and automatically resolved. These functions are generated for up to 20 dependencies. Checkout the code for more info.

Operators

This extension also aims to reduce the amount of boilerplate while improving readability of the registration code. For that reason the operator ~> is introduced.

Petowner(pet: r~>)

// equivalent to

Petowner(pet: r.resolve(Animal.self)!)

The dependency is again inferred from the type in the initializer. To specify a concrete class you can use:

Petowner(pet: r ~> Cat.self)

To use a named service:

Petowner(pet: r ~> (Cat.self, name: "mimi"))

or to pass argument/s:

Petowner(pet: r ~> (Cat.self, argument: "Mimi"))
Petowner(pet: r ~> (Cat.self, arguments: ("Mimi", UIColor.black)))

Limitations

When a service has multiple initializers, swift compiler can't be sure which should be used and you will get a ambigious use of init(x: y: z:). This can also happen if the service is extending another class that have initializer with the same number of arguments.

The solution is to specify the initializer like this:

container.autoregister(Person.self, initializer: PetOwner.init(name:pet:))

Auto-registration can't be used with named dependencies in their initializers. There is no way to get a name of dependency from the initializer. For example, following code can't be auto-registered:

container.register(Animal.self, name: "mimi") { _ in Cat(name: "Mimi") }
container.register(Animal.self, name: "charles") { _ in Cat(name: "Charles") }
container.register(Person.self) {
    PetOwner(pet: r.resolve(Animal.self, name: "mimi")
}

Swift 5.3

Since Swift 5.3 the compiler behaves differently when infering initializers in structs that have variables with a default value:

struct Cat {
    let height: Int = 50
}

Compiler will generate two init functions:

Cat.init and Cat.init(height:)

Since the Swift 5.3 the following registration

container.autoregister(Animal.self, initializer: Cat.init)

will try to use the Cat.init(height:) which will then fail with Unresolved service: Int Initializer: (Int) -> Animal

Solution is to make the compiler use the init without a parameter

container.autoregister(Animal.self, initializer: Cat.init as () -> Cat)

Credits

SwinjectAutoregistration generics is inspired by:

License

MIT license. See the LICENSE file for details.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].