Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/Liftric/DIKit

Dependency Injection Framework for Swift, inspired by KOIN.
https://github.com/Liftric/DIKit

application-context carthage cocoapods dependency dependency-injection dependency-injection-container helper injection injection-container injection-dependency injection-framework ios koin service-locator swift swift-package-manager swift5 swiftpm

Last synced: 10 days ago
JSON representation

Dependency Injection Framework for Swift, inspired by KOIN.

Awesome Lists containing this project

README

        

# DIKit

Dependency Injection Framework for Swift, inspired by [KOIN](https://insert-koin.io/). Basically an implementation of service-locator pattern, living within the application's context.

> Grow as you go!

We started small, it perfectly fits our use case.

## Installation

### Via Carthage

DIKit can be installed using [Carthage](https://github.com/Carthage/Carthage). After installing Carthage just add DIKit to your Cartfile:

```ogdl
github "Liftric/DIKit" ~> 1.6.1
```

### Via CocoaPods

[CocoaPods](http://cocoapods.org) is a dependency manager for Swift and Objective-C Cocoa projects. After installing CocoaPods add DIKit to your Podfile:

```ruby
platform :ios, '9.0'
pod 'DIKit', '~> 1.6.1'
```

## Basic usage

1. Define some sub `DependencyContainer` (basically some sort of module declaration):
```swift
import DIKit

public extension DependencyContainer {
static var backend = module {
single { Backend() as BackendProtocol }
}
}

public extension DependencyContainer {
static var network = module {
single { Network() as NetworkProtocol }
}
}

public extension DependenyContainer {
static var app = module {
single { AppState() as AppStateProtocol }
factory { StopWatch() as StopWatchProtocol }
}
}
```

2. Set the root `DependencyContainer` and set it before the application gets initialised:
```swift
import DIKit

@UIApplicationMain
class AppDelegate: UIApplicationDelegate {
override init() {
super.init()
DependencyContainer.defined(by: modules { .backend; .network; .app })
}
}
```

Without sub `DependencyContainer` the following shorthand writing also does the job:

```swift
import DIKit

@UIApplicationMain
class AppDelegate: UIApplicationDelegate {
override init() {
super.init()
DependencyContainer.defined(by: module {
single { AppState() as AppStateProtocol }
factory { StopWatch() as StopWatchProtocol }
})
}
}
```

3. Inject the dependencies, for instance in a module:
```swift
import DIKit

class Backend: BackendProtocol {
@Inject var network: NetworkProtocol
}
```

or a `ViewController`:
```swift
import DIKit

class FirstViewController: UIViewController {
// MARK: - Dependencies
@LazyInject var backend: BackendProtocol
@OptionalInject var stopwatch: StopWatchProtocol?

// MARK: - View lifecycle
override func viewWillAppear(_ animated: Bool) {
let result = backend.fetch()
print(result)
}
}
```

Injection via constructor:

```swift
import DIKit

struct AppState: AppStateProtocol {
private let backend: BackendProtocol
init(backend: BackendProtocol = resolve()) {
self.backend = backend
}
}
```

## Advanced usage
### Resolving by Tag

When registering your dependencies you can optionally define a tag. The tag can be anything, as long as it is `AnyHashable`.

This way you can register different resolvable dependencies for the same Type.

```swift
enum StorageContext: String {
case userdata
case systemdata
}

public extension DependencyContainer {
static var app = module {
factory(tag: StorageContext.systemdata) { LocalStorage() as LocalStorageProtocol }
factory(tag: StorageContext.userdata) { LocalStorage() as LocalStorageProtocol }
}
}
```

You can then reference the same tag when resolving the type and can thus resolve different instances. Referencing the tag works with all injection methods.

```swift
import DIKit

class Backend: BackendProtocol {
@Inject(tag: StorageContext.systemdata) var injectedStorage: LocalStorageProtocol
@LazyInject(tag: StorageContext.systemdata) var lazyInjectedStorage: LocalStorageProtocol
@OptionalInject(tag: StorageContext.systemdata) var optionalInjectedStorage: LocalStorageProtocol?

private let constructorInjectedStorage: LocalStorageProtocol
init(storage: LocalStorageProtocol = resolve(tag: StorageContext.systemdata)) {
self.constructorInjectedStorage = storage
}
}
```