Impose

1.1.2

Impose is a simple dependency injection library for Swift
nayanda1/Impose

What's New

Revert foldering

2021-02-19T08:09:04Z
  • Revert foldering
  • Added macOS, tvOS target
  • Added existing unit test to SPM

Impose

Impose is a simple dependency injection library for Swift

build test Version License Platform

Requirements

  • Swift 5.0 or higher
  • iOS 9.3 or higher

Installation

Cocoapods

Impose is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Impose'

Swift Package Manager

First, create a Package.swift file and add this github url. It should look like:

dependencies: [
    .package(url: "https://github.com/nayanda1/Impose.git", from: "1.2.0")
]

Then run swift build to build the dependency before you use it

Author

Nayanda Haberty, nayanda1@outlook.com

License

Impose is available under the MIT license. See the LICENSE file for more info.

Basic Usage

Impose is very easy to use and straightforward, all you need to do is provide some provider for dependency:

Imposer.impose(for: Dependency.self, SomeDependency())

and then use it in some of your class using property wrapper or using global function

class InjectedByPropertyWrapper {
    @Injected var dependency: Dependency
    
    ...
    ...
}

class InjectedByInit {
    var dependency: Dependency
    
    init(dependency: Dependency = inject()) {
        self.dependency = dependency
    }
}

the provider is autoClosure type, so you can do something like this:

Imposer.impose(for: Dependency.self) {
    dependency: SomeDependency = .init()
    dependency.doSomeSetup()
    return dependency
}

the provider automatically just create one instance only (singleton). If you want the provider to create new instance for every injection, you can just pass option:

Imposer.impose(for: Dependency.self, option: .alwaysNew, SomeDependency())

or if you want to set it to singleton explicitly:

Imposer.impose(for: Dependency.self, option: .singleton, SomeDependency())

Don't forget that it will throw uncatchable Error if the provider is not registered yet. If you want to catch the error manually, just use tryInject instead:

class InjectedByInit {
    var dependency: Dependency
    
    init(dependency: Dependency? = nil) {
        do {
            self.dependency = dependency ?? try tryInject()
        } catch {
            self.dependency = DefaultDependency()
        }
    }
}

Optional Inject

Sometimes you just don't want your app to be throwing error because of failure in dependency injection. At those cases, just use @UnforceInjected attribute or unforceInject function. It will return nil if injection fail:

```swift
class InjectedByPropertyWrapper {
    @UnforceInjected var dependency: Dependency?
    
    ...
    ...
}

class InjectedByInit {
    var dependency: Dependency
    
    init(dependency: Dependency? = unforceInject()) {
        self.dependency = dependency
    }
}

No Match Rules

If the Imposer did not found exact type registered but multiple compatible type, it will use the nearest one to the requested type.

protocol Dependency {
    ...
    ...
}

class MyDependency: Dependency {
    ...
    ...
}

class YourDependency: MyDependency {
    ...
    ...
}

class OurDependency: YourDependency {
    ...
    ...
}

and you register your dependency like this:

Imposer.impose(for: Dependency.self, MyDependency())
Imposer.impose(for: YourDependency.self, YourDependency())
Imposer.impose(for: OurDependency.self, OurDependency())

then the result will be:

class InjectedByPropertyWrapper {
    @Injected var thisWillBeMyDependency: Dependency
    @Injected var thisWillBeYourDependency: MyDependency
    @Injected var thisWillBeYourDependencyToo: YourDependency
    @Injected var thisWillBeOurDependency: OurDependency
    
    ...
    ...
}


class InjectedByInit {
    var thisWillBeMyDependency: Dependency
    var thisWillBeYourDependency: MyDependency
    var thisWillBeYourDependencyToo: YourDependency
    var thisWillBeOurDependency: OurDependency
    
    init(thisWillBeMyDependency: Dependency = inject(),
         thisWillBeYourDependency: MyDependency = inject(),
         thisWillBeYourDependencyToo: YourDependency = inject(),
         thisWillBeOurDependency: OurDependency = inject()) {
        self.thisWillBeMyDependency = thisWillBeMyDependency
        self.thisWillBeYourDependency = thisWillBeYourDependency
        self.thisWillBeYourDependencyToo = thisWillBeYourDependencyToo
        self.thisWillBeOurDependency = thisWillBeOurDependency
    }
}

If you prefer the furthest type registered, then you can pass rules into propertyWrapper or inject function like this:

class InjectedByPropertyWrapper {
    @Injected(ifNoMatchUse: .furthestType) 
    var thisWillBeMyDependency: Dependency
    
    @Injected(ifNoMatchUse: .furthestType) 
    var thisWillBeOurDependency: MyDependency
    
    @Injected(ifNoMatchUse: .furthestType) 
    var thisWillBeYourDependency: YourDependency
    
    @Injected(ifNoMatchUse: .furthestType) 
    var thisWillBeOurDependencyToo: OurDependency
    
    ...
    ...
}


class InjectedByInit {
    var thisWillBeMyDependency: Dependency
    var thisWillBeOurDependency: MyDependency
    var thisWillBeYourDependency: YourDependency
    var thisWillBeOurDependencyToo: OurDependency
    
    init(thisWillBeMyDependency: Dependency = inject(ifNoMatchUse: .furthestType),
         thisWillBeOurDependency: MyDependency = inject(ifNoMatchUse: .furthestType),
         thisWillBeYourDependency: YourDependency = inject(ifNoMatchUse: .furthestType),
         thisWillBeOurDependencyToo: OurDependency = inject(ifNoMatchUse: .furthestType)) {
        self.thisWillBeMyDependency = thisWillBeMyDependency
        self.thisWillBeOurDependency = thisWillBeOurDependency
        self.thisWillBeYourDependency = thisWillBeYourDependency
        self.thisWillBeOurDependencyToo = thisWillBeOurDependencyToo
    }
}

Description

  • Swift Tools 5.3.0

Dependencies

Last updated: Fri Feb 19 2021 20:18:47 GMT-0500 (GMT-05:00)