Swinject is a lightweight dependency injection framework for Swift.

Overview

Swinject

Travis CI Carthage compatible CocoaPods Version License Platforms Swift Version Reviewed by Hound

Swinject is a lightweight dependency injection framework for Swift.

Dependency injection (DI) is a software design pattern that implements Inversion of Control (IoC) for resolving dependencies. In the pattern, Swinject helps your app split into loosely-coupled components, which can be developed, tested and maintained more easily. Swinject is powered by the Swift generic type system and first class functions to define dependencies of your app simply and fluently.

Features

Extensions

Requirements

  • iOS 8.0+ / Mac OS X 10.10+ / watchOS 2.0+ / tvOS 9.0+
  • Swift 2.2 or 2.3
    • Xcode 7.0+
  • Swift 3
    • Xcode 8.0+
  • Swift 3.2, 4.x
    • Xcode 9.0+
  • Carthage 0.18+ (if you use)
  • CocoaPods 1.1.1+ (if you use)

Installation

Swinject is available through Carthage, CocoaPods, or Swift Package Manager.

Carthage

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

Swift 2.2 or 2.3

1.1.4 ">
github "Swinject/Swinject" ~> 1.1.4

Swift 3.x or 4.x

github "Swinject/Swinject"

# Uncomment if you use SwinjectStoryboard
# github "Swinject/SwinjectStoryboard"

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.

Swift 2.2 or 2.3

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', '~> 1.1.4'

Swift 3.x

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'

# Uncomment if you use SwinjectStoryboard
# pod 'SwinjectStoryboard'

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

Swift Package Manager

in Package.swift add the following:

dependencies: [
    // Dependencies declare other packages that this package depends on.
    // .package(url: /* package url */, from: "1.0.0"),
    .package(url: "https://github.com/Swinject/Swinject.git", from: "2.7.1")
],
targets: [
    .target(
        name: "MyProject",
        dependencies: [..., "Swinject"]
    )
    ...
]

Documentation

Basic Usage

First, register a service and component pair to a Container, where the component is created by the registered closure as a factory. In this example, Cat and PetOwner are component classes implementing Animal and Person service protocols, respectively.

let container = Container()
container.register(Animal.self) { _ in Cat(name: "Mimi") }
container.register(Person.self) { r in
    PetOwner(pet: r.resolve(Animal.self)!)
}

Then get an instance of a service from the container. The person is resolved to a pet owner, and playing with the cat named Mimi!

let person = container.resolve(Person.self)!
person.play() // prints "I'm playing with Mimi."

Where definitions of the protocols and classes are

protocol Animal {
    var name: String? { get }
}

class Cat: Animal {
    let name: String?

    init(name: String?) {
        self.name = name
    }
}

and

protocol Person {
    func play()
}

class PetOwner: Person {
    let pet: Animal

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

    func play() {
        let name = pet.name ?? "someone"
        print("I'm playing with \(name).")
    }
}

Notice that the pet of PetOwner is automatically set as the instance of Cat when Person is resolved to the instance of PetOwner. If a container already set up is given, you do not have to care what are the actual types of the services and how they are created with their dependency.

Where to Register Services

Services must be registered to a container before they are used. The typical registration approach will differ depending upon whether you are using SwinjectStoryboard or not.

The following view controller class is used in addition to the protocols and classes above in the examples below.

class PersonViewController: UIViewController {
    var person: Person?
}

With SwinjectStoryboard

Import SwinjectStoryboard at the top of your swift source file if you use Swinject v2 in Swift 3.

// Only Swinject v2 in Swift 3.
import SwinjectStoryboard

Services should be registered in an extension of SwinjectStoryboard if you use SwinjectStoryboard. Refer to the project page of SwinjectStoryboard for further details.

extension SwinjectStoryboard {
    @objc class func setup() {
        defaultContainer.register(Animal.self) { _ in Cat(name: "Mimi") }
        defaultContainer.register(Person.self) { r in
            PetOwner(pet: r.resolve(Animal.self)!)
        }
        defaultContainer.register(PersonViewController.self) { r in
            let controller = PersonViewController()
            controller.person = r.resolve(Person.self)
            return controller
        }
    }
}

Without SwinjectStoryboard

If you do not use SwinjectStoryboard to instantiate view controllers, services should be registered to a container in your application's AppDelegate. Registering before exiting application:didFinishLaunchingWithOptions: will ensure that the services are setup appropriately before they are used.

Bool { // Instantiate a window. let window = UIWindow(frame: UIScreen.main.bounds) window.makeKeyAndVisible() self.window = window // Instantiate the root view controller with dependencies injected by the container. window.rootViewController = container.resolve(PersonViewController.self) return true } } ">
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    let container: Container = {
        let container = Container()
        container.register(Animal.self) { _ in Cat(name: "Mimi") }
        container.register(Person.self) { r in
            PetOwner(pet: r.resolve(Animal.self)!)
        }
        container.register(PersonViewController.self) { r in
            let controller = PersonViewController()
            controller.person = r.resolve(Person.self)
            return controller
        }
        return container
    }()

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

        // Instantiate a window.
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.makeKeyAndVisible()
        self.window = window

        // Instantiate the root view controller with dependencies injected by the container.
        window.rootViewController = container.resolve(PersonViewController.self)

        return true
    }
}

Notice that the example uses a convenience initializer taking a closure to register services to the new instance of Container.

Play in Playground!

The project contains Sample-iOS.playground to demonstrate the features of Swinject. Download or clone the project, run the playground, modify it, and play with it to learn Swinject.

To run the playground in the project, first build the project, then select Editor > Execute Playground menu in Xcode.

Example Apps

  • SwinjectSimpleExample demonstrates dependency injection and Swinject in a simple weather app that lists current weather information at some locations.
  • SwinjectMVVMExample demonstrates dependency injection with Swift and reactive programming with ReactiveCocoa in MVVM architecture.

Blog Posts

The following blog posts introduce Swinject and the concept of dependency injection.

Contribution Guide

A guide to submit issues, to ask general questions, or to open pull requests is here.

Question?

  • Slack feel free to discuss anything Swinject related.
  • Stack Overflow we are trying to monitor questions tagged swinject

Credits

The DI container features of Swinject are inspired by:

and highly inspired by:

License

MIT license. See the LICENSE file for details.

Comments
  • Recursive `resolve()` deadlocks with `synchronize()`-d resolver

    Recursive `resolve()` deadlocks with `synchronize()`-d resolver

    I see that internally the SynchronizedResolver class uses container's SpinLock (which is NSLock) to make locks. Can we change the NSLock to NSRecursiveLock here?

    BTW, here's my use case (simplified of course - I do have concurrency):

    public class A {
        private let b: B
        init(with r: Resolver) {
            b = r.resolve(B.self)    // this dead locks!
        }
    }
    private class B {}
    
    let c = Container()
    let threadSafeResolver = c.synchronize()
    
    c.register(A.self, factory: { _ in return A(with: threadSafeResolver) })
    c.register(B.self, factory: { _ in return B() })
    
    threadSafeResolver.resolve(A.self)
    
    question 
    opened by serges147 30
  • Use reflection for auto-injections?

    Use reflection for auto-injections?

    In Typhoon we can mark a property as auto-injectable, but it works for Objective-C only. I think Swinject could use the power of Mirror type [1], [2] to find properties we can automatically resolve. I think of UIViewControllers and SwinjectStoryboard enhancement, so we could get rid of setup extension method in favour of the code like this (I tried to patсh SwinjectStoryboard class):

    private func injectDependency(viewController: UIViewController) {
            //get the reflection info
            let mirror = Mirror(reflecting: viewController)
            //enumerate properties
            for case let (label?, anyValue) in mirror.children {
                let propMirror = Mirror(reflecting: anyValue)
                //I couldn't find a better way to detect auto-injectable properties =) 
                if label.substringToIndex(label.startIndex.advancedBy(6, limit: label.endIndex)) == "inject" {
                    //in here we could use propMirror.subjectType as dynamicType to find the type to be instantiated
                   //I tried to register this var with registerForStoryboard with no success, maybe you could help here?:
                   //Cannot invoke 'resolve' with an argument list of type '(Any.Type)'
                    SwinjectStoryboard.defaultContainer.registerForStoryboard(viewController.dynamicType, initCompleted: { r, c in
                        viewController.setValue(r.resolve(propMirror.subjectType), forKey: label)
                    })
                }
            }
    
            let registrationName = viewController.swinjectRegistrationName
            container.runInitCompleted(viewController.dynamicType, controller: viewController, name: registrationName)
    
            for child in viewController.childViewControllers {
                injectDependency(child)
            }
        }
    

    If we could solve resolving from mirror.subjectType, then we can later have dynamic property in ViewController like this:

    dynamic var injectWeatherFetcher: WeatherFetcher?
    

    dynamic var is important part - setValue works with @objc or dynamic vars.

    What do you think?

    enhancement 
    opened by Sega-Zero 28
  • Auto-registration

    Auto-registration

    Hello, first I would like to thank you for this awesome project!

    We are using Swinject extensively on our project and are too lazy to write all the code to register our services. I have come up with extension based on generics that makes our life easier:

    For my example I have this registration code:

    container.register(MasterViewModeling.self) { r in
         MasterViewModeling(api: r.resolve(APIServicing.self)!, geocoder: r.resolve(Geocoding.self)!, locationManager: r.resolve(LocationManaging.self)!, detailModelFactory: r.resolve(DetailViewModelFactory.self)!)
    }
    

    If I extend Resolvable I can use power of generics and custom operator

    extension Resolvable {
        func resolve<Service>() -> Service? {
           return self.resolve(Service.self)
        }
    }
    
    postfix operator ~ {}
    postfix func ~ <Service>(r: ResolverType) -> Service {
        return r.resolve()!
    }
    

    And my registration can be significantly shorter, given that I resolve nameless services without arguments (which is usually the case):

    container.register(MasterViewModeling.self) { r in
         MasterViewModeling(api: r~, geocoder: r~, locationManager: r~, detailModelFactory: r~)
    }
    

    This is significantly shorter, but we can do even more. I took inspiration in Curry and find out that we can use initializer's type to infere its dependencies. Creating new register(initializer:service:) method:

    func register<Service, A, B, C, D>(initializer initializer: (A, B, C, D) -> Service, service: Service.Type, name: String? = nil) -> ServiceEntry<Service> {
       return self.register(service.self, name: name, factory: { r in 
           initializer(r.resolve()!, r.resolve()!, r.resolve()!, r.resolve()!)
       } as (Resolvable) -> Service)
    }
    

    We get registration:

    container.register(initializer: MasterViewModel.init, service: MasterViewModeling.self)
    

    This is awesome, because even when I add new dependency I don't have to change my container registration code.

    This method have to be generated for every number of dependencies, in a same way as Curry. See generated source code

    I have written a script that does exactly that, so the number of dependencies can be dynamically changed. (I am not sure if .erb is strong enough to be able to generate it, so I wrote it in swift, see the script )

    I also often pass dynamic arguments to my services, but don't want to write the whole register factory. By creating register(initializer:service:argument:) method:

    func resolve<Service, Arg1>(argument argument: (Arg1)) -> Service? {
       return (argument as? Service) ?? self.resolve(Service.self, argument: argument)
    }
    
    func register<Service, A, B, C, D, Arg1>(initializer initializer: (A, B, C, D) -> Service, service: Service.Type, name: String? = nil, argument: (Arg1.Type)) -> ServiceEntry<Service> {
       return self.register(service.self, name: name, factory: { r, arg1 in 
           initializer(r.resolve(argument: (arg1))!, r.resolve(argument: (arg1))!, r.resolve(argument: (arg1))!, r.resolve(argument: (arg1))!)
       } as (Resolvable, Arg1) -> Service)
    }
    
    

    we can than register like this. The dynamic argument is tested against all dependencies (in runtime) in initializer and if it fits the type it is passed instead of resolving dependency.

    container.register(initializer: MasterViewModel.init, service: MasterViewModeling.self, argument: MyDynamicArgument.self )
    

    This is not compiler safe though, but given that there can be multiple arguments and multiple dependencies on different positions, the number of permutation that would have to be generated is pretty hight. If we would force users to pass dynamic arguments as first and dependencies after them, it could be made compiler safe. But I think it would only lead to confusion.

    Now, there are obviously some drawbacks. If you have two initializers in one class, compiler doesn't know which one to choose. Also if you have two inits in same class hierarchy and they have same number of arguments there will be a conflict. (e.g. UIViewController(coder: NSCoder) and MyViewController(viewModel: ViewModel))

    You can either create custom named init, and use it for registration:

    class func swinit(api: APIServicing, geocoder: Geocoding, locationManager: LocationManaging, detailModelFactory: DetailModelingFactory){
        return self.init(....)
    }
    

    ~~Or perform some swift magic and convince compiler to use your init. Sometimes during writing it causes bug in compiler which then runs on 200% CPU, but once written it is ok. You have been warned :P.~~

    You can force the compiler to choose specific init. This is probably better option.

    container.register(initializer: MasterViewModel.init(api:geocoder:locationManager:detailModelFactory:), service: MasterViewModeling.self)
    

    Also, if you have an optional dependency in your init, the autoregistration won't work. For the registration:

    func register<Service, A, B, C, D, Arg1>(initializer initializer: (A, B, C, D)
    

    There could be many permutations like (A?, B, C, D), (A?, B?, C, D), (A, B, C, D?) ... which is impossible to generate for more than few dependencies.

    And of course, if you have named services, or more complex registration you will have to use current registration factories.

    This issue is meant to start discussion whether auto-registration should be part of swinject. On my part, I am pretty happy with the extension, it reduced our container file by a large margin, but we don't use all features of swinject so there might be additional problems.

    enhancement 
    opened by tkohout 25
  • DI with NIB/XIB

    DI with NIB/XIB

    Hey there,

    I'm currently trying to get Swinject running. However, I'm struggling heavily to get the injection up and running. In my Setting.class, the property "dataSource" is always nil as it's not getting injected. What am I doing wrong? Looking for advice :)

    Regards, Manuel

    extension SwinjectStoryboard {
        class func setup() {
    
            defaultContainer.registerForStoryboard(SettingsPreferencesController.self) {r, c in
                c.settings = r.resolve(Setting.self)
            }
    
            defaultContainer.register(DataSource.self) { _ in RealmService() }
            defaultContainer.register(Setting.self) { r in
                let setting = Setting()
                setting.dataSource = r.resolve(DataSource.self)
                return setting
            }
        }
    }
    
    protocol SettingType {
        var sourceHost: String? { get set }
        var sourceRoot: String? { get set }
        var dataSource: DataSource? { get set }
    }
    
    class Setting : Object , SettingType  {
    
        var dataSource: DataSource? = nil
    
        dynamic var sourceHost: String? = nil
        dynamic var sourceRoot: String? = nil
    
        override static func ignoredProperties() -> [String] {
            return ["dataSource"]
        }
    
        static func getSetting() -> Setting? {
            return RealmService().realm.objects(Setting).first
        }
    
        func save() {
            dataSource!.write(self)
        }
    }
    
    import Foundation
    
    protocol DataSource {
        func write(itemToWrite : AnyObject)
    }
    
    class RealmService : DataSource {
    
        let realm = try! Realm()
    
        func write(itemToWrite: AnyObject) {
            let object = itemToWrite as! Object
            try! realm.write() {
                realm.add(object, update: true)
            }
        }
    }
    
    question 
    opened by SantoDE 22
  • Swinject crashes swiftc in Xcode 9

    Swinject crashes swiftc in Xcode 9

    When building Swinject with Xcode 9, Swinject causes a segmentation fault in swiftc. I know this isn't your fault (the compiler shouldn't crash) but I thought I should mention it here. I've also filed this with Apple as rdar://32589507

    To reproduce: Clone the repo as it is right now. Open Swinject.xcodeproj in Xcode 9. Build. Swiftc will have a segmentation fault and die, causing a build failure.

    question 
    opened by atomicbird 21
  • Pass assembler while assembling containers

    Pass assembler while assembling containers

    This is not an issue, but a suggestion/idea.

    Assume I have a RootController and RootRouter. The last one is responsible for presenting (modal/push, animation, etc) other controllers. I want to present AnimalController (which has it's own dependencies).

    I have the following assemblies diagram:

    • RootAssembly
      • RootController AssemblyType
      • Services AssemblyType (api, db, etc)
    • AnimalAssembly.

    After #50 I can make animal assembly with parent assembly (I really need to access db from AnimalController).

    So here is the problem:

    class RootControllerContainer: AssemblyType {
    
        func assemble(container: Container) {
    
            container.register(RootController.self) { r in
                RootController(router: r.resolve(RootRouter.self)!)
            }
    
            container.register(RootRouter.self) { _ in
                RootRouter()
            }
        }
    }
    

    Now I'd like to create a AnimalController inside RootRouter.swift:

    func showDogDetails(dog: Dog) {
        let animalController = ???
        rootController.navigationController.pushViewController(animalController, animated: true)
    }
    

    So the question is how do I construct AnimalAssembly with RootAssembly? When we were working with Containers I was able to create new container with given parent.

    So I suggest: Pass assembler reference in assemble func, so I can register components, that is dependant on this assembler.

    question 
    opened by Nikita2k 21
  • API for resolving dependencies with arguments is typo-prone

    API for resolving dependencies with arguments is typo-prone

    After it took us a while of staring at the code to figure out the source of bug, we've identified a place for possible improvement in Swinject API:

    Consider following lines:

    container.resolve(SomeType.self, argument:(a, b, c))
    container.resolve(SomeType.self, arguments:(a, b, c))
    

    The difference in syntax is IMO much more difficult to spot than it should be, and main problem is that both lines are perfectly valid, except former most often does not capture the intent.

    Some alternative syntaxes that come to mind:

    // change the param name
    container.resolve(SomeType.self, multipleArguments: (a, b, c)) 
    
    // use variadic params
    container.resolve(SomeType.self, arguments: a, b, c)`
    

    Thoughts?

    enhancement help wanted 
    opened by jakubvano 20
  • CocoaPods 1.0 Build Error 'Swinject/_SwinjectStoryboardBase.h' file not found

    CocoaPods 1.0 Build Error 'Swinject/_SwinjectStoryboardBase.h' file not found

    After upgrading to CocoaPods 1.0.0 this morning, I've getting a compile time error with Swinject.

    /Users/myuser/Documents/Github/myrepo/Pods/Swinject/Sources/Swinject.h:23:9: 'Swinject/_SwinjectStoryboardBase.h' file not found
    

    I found this issue but my target is set to iOS 9.3, so I didn't think it was relevant.

    Everything was working on CocoaPods 0.39.0

    opened by bclymer 16
  • Long Term Support

    Long Term Support

    I have recently been informed about Swinject by other colleges. I do however see that it's been some time since any commits have been made.

    Could one of the contributors confirm that this library will be supported over the next coming years.

    Thanks

    opened by davidthorn 14
  • Resolve object lazily

    Resolve object lazily

    Hello!

    In some cases we need to create wrapper like a ViewFactory or something like it. In general it is lazy initialization, so would be nice if Swinject will support lazy initialization. It can be implemented as struct that contains Closure to resolve object. example of implementation below:

    // Object will be common if someone have a strong reference
    public struct Lazy<Service> {
        private let initClosure: () -> Service?
        private var service: Service?
        
        internal init(initClosure: () -> Service?) {
            self.initClosure = initClosure
        }
        
        public func resolve() -> Service? {
            if service == nil {
                service = initClosure()
            }
            return service
        }
    }
    

    What you think about it?

    enhancement 
    opened by AnisovAleksey 13
  • Potential crash in Swinject due to unwanted call for `resetObjectScope`

    Potential crash in Swinject due to unwanted call for `resetObjectScope`

    Hi there, I'm investigating a production crash we're experiencing in our app. While going over the crash log provided by Crashlytics, I'm seeing some worrisome lines in the stack trace, stating the app crashed while calling resetObjectScope a few times while trying to add a child view controller by instantiating and injecting its dependancy using SwinjectStoryboard... I'm a bit confused with this as we're only calling resetObjectScope explicitly on specific cases (and not this one).

    Thanks in advance, Gil

    0 | libsystem_kernel.dylib | __pthread_kill + 8 -- | -- | -- 1 | libsystem_pthread.dylib | pthread_kill$VARIANT$armv81 + 360 2 | libsystem_c.dylib | abort + 140 3 | libsystem_malloc.dylib | szone_size + 634 4 | libswiftCore.dylib | _swift_release_dealloc + 28 5 | Swinject | _T08Swinject16PermanentStorageCAA08InstanceC0A2aDP8instanceypSgfsTW + 84 6 | Swinject | T08Swinject9ContainerC16resetObjectScopeyAA0dE8Protocol_pFyAA012ServiceEntryF0_pcfU0 + 176 7 | Swinject | _T0s8SequencePsE7forEachyy7ElementQzKcKFTfq4gn_nSay8Swinject20ServiceEntryProtocol_pG_Tg5 + 232 8 | Swinject | _T08Swinject9ContainerC16resetObjectScopeyAA0dE8Protocol_pFTf4gn_n + 192 9 | Swinject | _T08Swinject9ContainerC8_resolvexSgSSSg4name_AA16ServiceKeyOption_pSg6optionxq_c7invokertr0_lF + 1700 10 | Swinject | _T08Swinject9ContainerCAA9_ResolverA2aDP8_resolveqd__SgSSSg4name_AA16ServiceKeyOption_pSg6optionqd__qd_0_c7invokertr0_lFTW + 128 11 | SwinjectStoryboard | _T018SwinjectStoryboardAAC16injectDependency33_5D9C018A2F8973BF429DA54A673A2489LLySo16UIViewControllerC2to_tFTf4gn_n + 948 12 | SwinjectStoryboard | _T018SwinjectStoryboardAAC25instantiateViewControllerSo06UIViewE0CSS14withIdentifier_tFTf4gXn_n + 428 13 | SwinjectStoryboard | _T018SwinjectStoryboardAAC25instantiateViewControllerSo06UIViewE0CSS14withIdentifier_tFTo + 52 14 | MyApp | StatusViewController.swift line 34StatusViewChild.controller.getter -- | -- | -- 15 | MyApp | StatusViewController.swift line 370StatusViewController.addController(ofType : StatusViewChild, toSide : StatusViewController.ChildSide) -> () 16 | MyApp | StatusViewController.(setupBindings() -> ()).(closure #11) + 4367383352 17 | MyApp | StatusViewController.swift line 0partial apply for StatusViewController.(setupBindings() -> ()).(closure #13) 18 | MyApp | MapViewController.swift line 0thunk ...

    opened by gilgol 12
  • UIFoundation: UINibDecoderDecodeObjectForValue exception iOS 16

    UIFoundation: UINibDecoderDecodeObjectForValue exception iOS 16

    We use Swinject 2.8.0 in production and from the latest version and from iOS 16 (but not only, we have some users from 15.6.1) we have a raising issue. The app is crashing on start. In Xcode I see some crash reports but I can not reporduce the issue (tested on like 20 devices). Screenshot 2022-10-03 at 15 37 07 I'll try 2.8.2 but from the release notes I see it's only typo fixes... so I don't know what to do. Any help? Others maybe have the same problem? Screenshot 2022-10-03 at 15 36 02

    opened by glizik 2
  • Overloaded bindings in hierarchy of assemblers are resolved in a incorrect way

    Overloaded bindings in hierarchy of assemblers are resolved in a incorrect way

    Hi, nazdar,

    I make use of the parent child assemblers, which works great to create semantical scopes.

    However one thing that is unexpected/dangerous is how unnamed overloaded bindings are resolved, when in a hierarchy

    Say I have a alamofire Interceptor registered in app scope, which provides a common middleware for attaching user agent etc container.register(Interceptor.self, name: "app") { _ in Interceptor([ some common interceptors ])

    This is then wrapped by RequestHelper as to not expose alamofire types

    protocol RequestHelper
    
    final class RequestHelperImpl : RequestHelper {
       private let interceptor: Interceptor
    }
    
    ...
    container.register(RequestHelper.self) { r in
       RequestHelper(r.resolve(name: "app")
    }
    

    Then a feature 1 has a api client, whose logical scope is app scope container.register(Feature1ApiClient.self) { r in FeatureApi1Client(requestHelper: r.resolve(RequestHelper.self)

    This seems to work fine

    Then user scope is added, which obviously needs a way to authenticate the request, while inheriting the app scope behaviour (interceptor)

    container.register(Interceptor.self, name: "user") { r in
       let parentInterceptor = r.resolve(Interceptor.self, name: "app")
       return Interceptor([parentInterceptor, AuthenticationInterceptor()
    }
    
    container.register(RequestHelper.self) { r in
       RequestHelper(r.resolve(name: "user")
    }
    

    Now comes feature 2 which is in the user scope container.register(Feature2ApiClient.self) { r in FeatureApi2Client(requestHelper: r.resolve(RequestHelper.self)

    And the assemblers are instantiated like this (so AppScope is parent to UserScope)

    let appScopeAssembler = Assembler([Feature1Assembly()], parent: nil)
    let userScopeAssembler = Assembler([Feature2Assembly()], parent: appScopeAssembler)
    

    Ooookay, now, the issue is, that both RequestHelpers are registered anonymously, and this I believe should be okay, as both are NOT reqistered in the same scope but different scopes - yes, app scope is parent to user scope, so user scope technically sees 2 bindings, but, the "scope local" should be the first choice - and it mostly behaves in this way, given the sources

    fileprivate func getEntry(for key: ServiceKey) -> ServiceEntryProtocol? {
        if let entry = services[key] {
            return entry
        } else {
            return parent?.getEntry(for: key)
        }
    }
    

    The unexpected part comes, when user assembler.resolve is used to resolve a app scope binding, which again, is all legal let feature1ApiClient = userScopeAssembler.resolve.resolve(Feature1ApiClient.self)

    HOWEVER the RequestHelper instance of FeatureApi1Client(requestHelper: r.resolve(RequestHelper.self) is the one registered in user scope, not app scope as indended!

    Obviously this all could be alleviated by naming the RequestHelper bindings, however this then breaks encapsulation, and which RequestHelper instance is uses should only be dictated by where the XAssembly is added to.

    I did concede in naming the Interceptor bindings as there I need to explicitly as for parent Interceptor, and this only happens once per scope, so total of 2, which I could live with.

    But I'm not keen on breaking the encapsulation everywhere as there are going to be 10s of features per scope, and paying such close attention on which scope the instance is resolved is very error prone.

    Thoughts?

    opened by ursusursus 0
  • Deallocated variable when trying to resolve object

    Deallocated variable when trying to resolve object

    Im trying to resolve viewModel in my MVVM architecture

    My assembly class

    public final class CancelAssembly: Assembly {
        
        public init() {
            
        }
        
        var container: Swinject.Container?
        var viewController: UIViewController!
        
        public func assemble(container: Swinject.Container) {
            container.register(CancelCoordinatorProtocol.self,
                               factory: {(r, assembler: Assembler?, rootViewController: UINavigationController, order: Order) -> CancelCoordinator in CancelCoordinator(rootNavigationController: rootViewController, assembler: assembler, order: order)
            }).inObjectScope(.transient)
            
            container.register(CancelViewControllerProtocol.self, factory: {(r, viewModel: CancelViewModel) -> CancelViewController in
                return CancelViewController(viewModel: viewModel)
            }).inObjectScope(.graph)
            
            container.register(CancelRouterProtocol.self, factory: {(r, routes: StrongRouter<CancelRoute>) -> CancelRouter in
                return CancelRouter(routes: routes)
            }).inObjectScope(.graph)
            
            container.register(CancelViewModelProtocol.self,
                               factory: {(r, router: StrongRouter<CancelRoute>, order: Order, step: Int) -> CancelViewModel in
                let router = r.resolve(CancelRouterProtocol.self, argument: router) as! CancelRouter
                let viewModel = CancelViewModel(router: router, order: order, step: step)
                let vc = r.resolve(CancelViewControllerProtocol.self, argument: viewModel) as? CancelViewController
                viewModel.viewController = vc
                return viewModel
            }).inObjectScope(.graph)
            
        }
    
    }
    

    Trying to resolve this way

    let vm = assembler?.resolver.resolve(CancelViewModelProtocol.self, arguments: strongRouter, order, index) as? CancelViewModel

    When I resolve it first time all is working correctly But second time it gives me nil in viewModel.viewController I checked that my CancelViewController deinited after 'return viewModel', but in first time it is ok.

    viewModel has weak reference to viewController and viewController has strong reference to viewModel

    What am I doing wrong?

    opened by EgorkZe 1
  • Multibinding support?

    Multibinding support?

    Coming from android / Dagger side of the world, the thing I'm missing to facilitate a highly modular codebase is multibinding. Essential, what it is, is that the implementation is registered as its protocol type - the usual stuff.

    However, I'm then able to be pull out (inject) all these protocol-implementing instances as a set or array, i.e. Set<SomePlugin>

    This allows for a plugin architecture which is a necessity in a multi-app modular shared codebase

    opened by ursusursus 4
  • Unable to update to the latest version of Swinject as SwinjectStoryboard depends on an older version of Swinject

    Unable to update to the latest version of Swinject as SwinjectStoryboard depends on an older version of Swinject

    SwinjectStoryboard depends on Swinject 2.7.1. Since we use SwinjectStoryboard in our project, this has been blocking us from using the latest Swinject version. There is an open issue 169 highlighting this problem. I'm creating this issue here in the hope that SwinjectStoryboard and Swinject might have some common maintainers. Please take a look at it.

    Thank you. James

    opened by sskjames 1
Releases(2.8.3)
  • 2.8.3(Dec 2, 2022)

    Enhancement

    • Adds hasAnyRegistration Container method (thanks @oronbz!)
    • Add test target to SPM package (thanks @bradfol!)
    • SynchonizedResolver cleanup (thanks @welshm!)

    Bugfix

    • Fix concurrency issue with GraphIdentifier & Lazy wrapper (@maxim-chipeev, & thanks @bradfol for import hotfix)
    Source code(tar.gz)
    Source code(zip)
  • 2.8.2(Aug 3, 2022)

  • 2.8.1(Oct 3, 2021)

    Compatibility

    • Remove excluded arm64 architecture for simulators so library can be used on M1 simulators (thanks @mateuszszklarek and @yoichitgy)
    • SPM versions update (thanks @mpdifran)

    Documentation

    • Readme updates (thanks @yoichitgy)
    Source code(tar.gz)
    Source code(zip)
  • 2.8.0(Aug 14, 2021)

    Compatibility

    We have made sure Swinject works with Xcode 12.5 and Swift 5.4!

    Enhancement

    • Enables support for distributing Swinject as a binary library (#451). Thanks @devioustree!
    • Support Xcode 12 (#461, #464). Thanks @mpdifran, @tkohout!
    • Add dynamic option for the library to SPM (#465). Thanks @mpdifran!
    • Add support for DocC (#471). Thanks @mpdifran!

    Other Contributions

    • Fixed/improved documentation (#444, #446, #447, #454, #479). Thanks @charlesmuchene, @ngeri, @thomasburguiere, @1ucas!
    • Remove dependency on Quick/Nimble (#473). Thanks @yoichitgy!
    • Update CI provider and fix Build Badge Address (#483). Thanks @1ucas!
    • Renamed SpinLock to RecursiveLock internally (#484). Thanks @1ucas!
    • Generate the project before tests (#485). Thanks @1ucas!

    Known Issue

    • ServiceKeyOption protocol got a breaking change on Swinject v2.7.0. We'll release v3.0.0 later to follow semantic versioning.

    This version supports Xcode 10.2+ with Swift 4.2+.

    Source code(tar.gz)
    Source code(zip)
  • 2.7.1(Sep 9, 2019)

    Bugfix

    • Fixed warning when integrating Swinject via Carthage into app extension (#435). Thanks @raptorxcz!

    This version supports Xcode 10.2+ with Swift 4.2+.

    Source code(tar.gz)
    Source code(zip)
  • 2.7.0(Sep 2, 2019)

    Compatibility

    Swinject has been migrated to Swift 5, thus we no longer support Xcode <10.2. Projects running on Xcode 10.2+ with codebase in older Swift should not be affected.

    Bugfix

    • Fixed duplicit bunde id issue in multiplatform projects (#433). Thanks @raptorxcz!

    This version supports Xcode 10.2+ with Swift 4.2+.

    Source code(tar.gz)
    Source code(zip)
  • 2.6.2(Jun 21, 2019)

    Bugfix

    • Fixed swift package manager integration (#414). Thanks @thbonk!
    • Fixed premature object graph termination (#418)

    This version supports Xcode 10+ with Swift 3.x / 4.2 / 5.

    Source code(tar.gz)
    Source code(zip)
  • 2.6.1(May 29, 2019)

  • 2.6.0(Mar 8, 2019)

  • 2.5.0(Sep 19, 2018)

    Compatibility

    • Added support for Xcode 10 & Swift 4.2 (#369, #371). Thanks @janhalousek, @ilijapuaca!

    Documentation

    • Replaced deprecated Resolvable with Resolver (#370). Thanks @acevif!

    This version supports Xcode 10 with Swift 3.x and 4.2.

    Source code(tar.gz)
    Source code(zip)
  • 2.4.1(Jun 5, 2018)

    Bugfix

    • added workaround for nested synchronized resolutions (#353, #350) Thanks @serges147, @gilroykilroy

    This version supports Xcode 9+ with Swift 3.x and 4.x.

    Source code(tar.gz)
    Source code(zip)
  • 2.4.0(Apr 5, 2018)

    Compatibility

    • added compatibility with Xcode 9.3 and Swift 4.1 (#342). Thanks @Vkt0r!

    This version supports Xcode 9+ with Swift 3.x and 4.x.

    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Mar 27, 2018)

    New features

    • Delayed Injection (#331, #303 ): We now have Lazy and Provider injection!
    • Type forwarding (#319): We can reuse one registration for multiple types!
    • Behaviors (#330, #322): Convenient way of adding custom steps to the registration process.

    Enhanced

    • Added support for multiple initCompleted definitions (#325). Thanks @AnisovAleksey!
    • Added default scope to the assembler initialisation (#323). Thanks @libec!
    • Added support for transparently resolving the optionals of the registered types (#334).

    Bugfix

    • Fixed an issue with .weak object scope in circular dependencies (#318)

    Documentation

    • Brought README up to date with Swift4 (#332). Thanks @acevif!

    This version supports Xcode 9+ with Swift 3.x and 4.

    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Feb 13, 2018)

    Enhanced

    • Added support for Xcode 9 (#294). Thanks @yoichitgy!
    • Added option to specify a default object scope (#291, #304). Thanks @jkaan!
    • Cleaned up hash computation (#298). Thanks @tarunon!
    • Cleaned up Swiftlint directives (#293). Thanks @knickmack!

    Documentation

    • Language improvements (#307) and playground warning fixes (#306). Thanks @gemmakbarlow!

    This version supports Xcode 9+ with Swift 3.x and 4.

    Source code(tar.gz)
    Source code(zip)
  • 2.1.1(Aug 14, 2017)

    Enhanced

    • Supported both Xcode 8.x and 9 beta. (#252, #262, #263, #281) Thanks @MadsBogeskov and @mackoj!
    • Cleaned up SwiftLint configurations. (#270) Thanks @jakubvano!
    • Add tests for the weak object scope. (#257) Thanks @mpdifran!
    • Remove Quick and Nimble submodules from this repository. (#259) Thanks @mpdifran!

    Documentation

    • Updated CONTRIBUTING.m. (#268) Thanks @jakubvano!
    • Fixed typos. (#255) Thanks @Lutzifer!

    This version supports Xcode 8.x and 9 beta with Swift 3.x and 4.

    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Apr 17, 2017)

    Fixed

    • Deprecated Assembler initializers throwing an error, and add initializers not throwing an error. (#241) Thanks @ManWithBear!
    • Fixed lint errors with SwiftLint v0.17.0. (#237) Thank @dagio!

    Documentation

    • Fixed a typo. (#230) Thanks @timbroder!
    • Fixed a type mistake. (#239) Thanks @rcfrias!
    • Added a compile performance remark. (#248) By @yoichitgy.

    This version supports Xcode 8.x with Swift 3.x.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Jan 8, 2017)

    Breaking Changes

    • Fixed typo in logingFunction property (#215). By @yoichitgy. Thanks @basalphenaar for the report!

    This version supports Xcode 8.x with Swift 3.0.x.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-beta.3(Dec 10, 2016)

    Breaking Changes

    • Renamed protocols for Swift 3 API conformance (#157, #203). By @jakubvano and @yoichitgy
    • Changed Assembler to final class (#193). By @yoichitgy
    • Removed .container object scope, and renamed .hierarchy scope to new .container scope (#165). By @jakubvano

    Enhanced

    • Made object scopes customizable (#165). By @jakubvano
    • Added .weak object scope (#198). By @jakubvano
    • Added logging of resolution failure (#160). By @jakubvano
    • Updated support of Swift Package Manager and Linux with Swift 3 (#196, #202). By @yoichitgy and @jakubvano

    Fixed

    • Added @escaping to the factory closure of register method (#194, #195). Thanks @kdubb!

    Documentation

    • Updated playground for Swift 3 (#167). By @jakubvano

    This version supports Xcode 8.1 with Swift 3.0.1.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.5(Oct 11, 2016)

    Fixed

    • Reverted postponing initCompleted calls (#164) which was causing some issues (#158, #159). A workaround for the original issue #133 is documented. Thanks @marcorei for collaboration!

    Enhanced

    • Added logging of resolution failure (#168) which should help with debugging. By @jakubvano.

    This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 with Swift 2.3.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-beta.2(Sep 11, 2016)

    Breaking Changes

    • Supported Swift 3 (#113). Thanks @garnett!

    Fixed

    • Fixed Package.swift to Swift Package Manager (#123)

    Documentation

    • Fixed typos (#120). Thanks @ybodson!
    • Fixed incorrect description about method injection (#142). Thanks @mpdifran!

    This version supports Xcode 8 (GM) with Swift 3.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.4(Sep 10, 2016)

    Fixed

    • Dependencies of ViewControllers are getting injected multiple times using reference Storyboards. (#125, #144) Thanks @jakubvano!
    • Dependencies of non-root UIViewControllers are not getting storyboard injected. (#128, #144) Thanks @jakubvano!
    • Updated the project settings as recommended by Xcode 8 (GM). (#145)

    This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 (GM) with Swift 2.3.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.3(Aug 29, 2016)

    Fixed

    • Extra instantiation of instances with circular dependency even in .Container scope. (#133, #134) Thanks @marcorei!

    Enhanced

    • Added SWIFT_VERSION = 2.3 to support both Xcode 7 and 8 (beta) in Swift 2. (#129) Thanks @thalmicMark!

    Internally enhanced

    • Replaced respondsToSelector call with optional chaining. (#109) Thanks @amccarri!

    This version supports Xcode 7.3 with Swift 2.2 and Xcode 8 (beta) with Swift 2.3.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-beta.1(Jul 1, 2016)

    Breaking Changes

    • Changed the API to resolve a service with multiple arguments (#63, #118). Thanks @jakubvano!
    • Moved SwinjectStoryboard to its own repository (#92). Specify it in your Cartfile or Podfile if you use it.
    • Moved SwinjectPropertyLoader to its own repository (#93). Specify it in your Cartfile or Podfile if you use it.
    • Renamed Resolvable to ResolverType protocol, and removed previous ResolverType typealias. (#90, #87).

    Enhanced

    • Replaced OSSpinLock with NSLock for safety against thread priority (#116). Thanks @noremac!
    • Replaced respondsToSelector call with optional chaining (#109). Thanks @amccarri!
    • Added CustomStringConvertible conformance to Container (#65, #66)

    The framework targets Swift 2.2 / Xcode 7.3.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.2(May 16, 2016)

    Fixed

    • Warnings for selectors with Swift 2.2 compiler (#101).

    Thanks @jlyonsmith for enhancing the documentation (#86) and updating dependencies in Cartfile (#85).

    The prebuilt framework targets Swift 2.2 / Xcode 7.3. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(5.38 MB)
  • 1.1.1(Mar 23, 2016)

    Added

    • Support of Xcode 7.3 / Swift 2.2 (#73, #75).

    Fixed

    • Carthage build error in some cases if a new version of SwiftLint is installed (#74).

    The prebuilt framework targets Swift 2.2 / Xcode 7.3. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(8.48 MB)
  • 1.1.0(Feb 6, 2016)

    Added

    • Assembly hierarchy (#50, #58). Thanks @Nikita2k, and @mowens for review!

    Fixed

    • Error on carthage build where a later version of SwiftLint is installed (#61, #60).

    Also, thanks @antonmes for improvement to README.

    The prebuilt framework targets Swift 2.1.1 / Xcode 7.2.x. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(8.27 MB)
  • 1.0.0(Dec 21, 2015)

    The first stable release 🎉

    No changes from v1.0.0 beta 3. Thanks @mowens for adding cool features, and everyone for submitting issues or using Swinject!

    The prebuilt framework targets Swift 2.1.1 / Xcode 7.2. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(8.17 MB)
  • 1.0.0-beta.3(Dec 12, 2015)

  • 1.0.0-beta.2(Dec 9, 2015)

    Added

    Enhanced

    • Replaced ServiceEntryBase with ServiceEntryType typealias to remove unnecessary inheritance of ServiceEntry type (#33)
    • Changed the accessibility of Box<T> class from public to internal to avoid conflict with types defined in the other frameworks or user's app.

    The prebuilt framework targets Swift 2.1.1 / Xcode 7.2. If you use another version of Xcode with Carthage, you might need to run carthage update command with --no-use-binaries option.

    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(8.59 MB)
  • 1.0.0-beta.1(Nov 27, 2015)

    This release targets Swift 2.1 / Xcode 7.1.

    Added

    • Thread safety: synchronize method on a container returns a thread safe view of the container. #29

    Enhanced

    • Removed usage of NSException to get rid of Objective-C dependency.

    Breaking change

    • Changed the signatures of resolve methods with registration name and arguments from resolve(_:arguments:name:) to resolve(_:name:arguments:) and from resolve(_:argument:name:) to resolve(_:name:argument:) for consistency with register methods. #30
    Source code(tar.gz)
    Source code(zip)
    Swinject.framework.zip(7.67 MB)
Owner
null
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

Aleksei Artemev 17 Oct 13, 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
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
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
Needle - Compile-time safe Swift dependency injection framework

Needle is a dependency injection (DI) system for Swift. Unlike other DI frameworks, such as Cleanse, Swinject, Needle encourages hierarchical DI struc

Uber Open Source 1.4k Jan 3, 2023
CarbonGraph - A Swift dependency injection / lookup framework for iOS

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

Baidu 244 Jan 4, 2023
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
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

Syed Sabir Salman-Al-Musawi 1 Oct 9, 2020
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

Siarhei Ladzeika 5 Dec 8, 2022
Toledo - a dependency injection library for Swift that statically generates resolvers at compile-time.

Toledo Toledo is a dependency injection library for Swift that statically generates resolvers at compile-time. Index Features Installation Usage Licen

Valentin Radu 18 Nov 25, 2022
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.

Michael Long 573 Jan 2, 2023
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

Maxim Bazarov 40 Dec 6, 2022
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

symentis GmbH 60 Nov 1, 2022
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.

Jungwon An 134 Aug 10, 2022
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

Olivier Halligon 949 Jan 3, 2023