Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/ivlevAstef/DITranquillity

Dependency injection for iOS (Swift)
https://github.com/ivlevAstef/DITranquillity

dependency-injection di di-container inversion-of-control ioc ios swift

Last synced: about 1 month ago
JSON representation

Dependency injection for iOS (Swift)

Awesome Lists containing this project

README

        


Tranquillity










# DITranquillity
Tranquillity is a lightweight but powerful [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) library for swift.

The name "Tranquillity" laid the foundation in the basic principles of library: clarity, simplicity and security.

It says - use the library and you will be calm for your dependencies.

> Language switch: [English](README.md), [Russian](README_ru.md)

## About Dependendy Injection
Dependency Injections is a software design pattern in which someone delivers dependencies to an object.

Is one form of the broader technique of [Inversion Of Control](https://en.wikipedia.org/wiki/Inversion_of_control) and help the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle)

[For more details you can read this link](Documentation/en/about_dependency_injection.md)

Also I recommend you to read [Glossary](Documentation/en/glossary.md) which will help to better understand the terms.

## Features
#### Core
- [x] [Registration components and services](Documentation/en/core/registration_and_service.md)
- [x] [Initializer/Property/Method Injections](Documentation/en/core/injection.md)
- [x] [Optional and argument, many, by tag Injections](Documentation/en/core/modificated_injection.md)
- [x] [Delayed injection](Documentation/en/core/delayed_injection.md)
- [x] [Circular dependency injection](Documentation/en/core/injection.md)
- [x] [Scope and lifetime](Documentation/en/core/scope_and_lifetime.md)
- [x] [Modular](Documentation/en/core/modular.md)
- [x] [Details logs](Documentation/en/core/logs.md)
- [x] Thread safety
- [x] [Container hierarchy](Documentation/en/core/container_hierarchy.md)
#### UI
- [x] [Storyboard and StoryboardReferences](Documentation/en/ui/storyboard.md)
- [x] [Simple subviews and Cells Injection](Documentation/en/ui/view_injection.md)
#### Graph API
- [x] [Get dependency graph](Documentation/en/graph/get_graph.md)
- [x] [Graph Validation](Documentation/en/graph/graph_validation.md)
- [ ] [Visualization dependency graph](Documentation/en/graph/visualization_graph.md)

## Installing
The library supports three popular package managers: Cocoapods, Carthage, SwiftPM.

#### CocoaPods
Add the following lines to your `Podfile`:
```
pod 'DITranquillity'
```

#### SwiftPM
You can use "Xcode/File/Swift Packages/Add Package Dependency..." and write github url:
```
https://github.com/ivlevAstef/DITranquillity
```

Also you can edit your `Package.swift` and the following line into section `dependencies`:
```Swift
.package(url: "https://github.com/ivlevAstef/DITranquillity.git", from: "4.6.0")
```
And don't forget to specify in your section `target` wrote dependency line:
```Swift
.product(name: "DITranquillity")
```
> Attention! - SwiftPM unsupport features from the "UI" section.

#### Carthage
Add the following lines to your `Cartfile`:
```
github "ivlevAstef/DITranquillity"
```
Carthage support "UI" and "GraphAPI" section no additional actions.

## Usage
The library uses a declarative style of dependency description, and allows you to separate your application code from dependency description code.

For a quick entry, let's look at an example code of one simplified VIPER screen:
```Swift
.................................................
/// Dependency description

let container = DIContainer()

container.register(LoginRouter.init)

container.register(LoginPresenterImpl.init)
.as(LoginPresenter.self)
.lifetime(.objectGraph)

container.register(LoginViewController.init)
.injection(cycle: true, \.presenter)
.as(LoginView.self)
.lifetime(.objectGraph)

container.register(AuthInteractorImpl.init)
.as(AuthInteractor.self)

.................................................
/// Application start point

let router: LoginRouter = container.resolve()
window.rootViewController = router.rootViewController
router.start()

.................................................
/// Application Code

import SwiftLazy

class LoginRouter {
let rootViewController = UINavigationController()
private let loginPresenterProvider: Provider

init(loginPresenterProvider: Provider) {
loginPresenterProvider = loginPresenterProvider
}

func start() {
let presenter = loginPresenterProvider.value
presenter.loginSuccessCallback = { [weak self] _ in
...
}
// Your can write code without force cast, it's code simple example
rootViewController.push(presenter.view as! UIViewController)
}
}

protocol LoginPresenter: class {
var loginSuccessCallback: ((_ userId: String) -> Void)?
func login(name: String, password: String)
}

protocol LoginView: class {
func showError(text: String)
}

class LoginPresenterImpl: LoginPresenter {
private weak var view: LoginView?
private let authInteractor: AuthInteractor
init(view: LoginView, authInteractor: AuthInteractor) {
self.view = view
self.authInteractor = authInteractor
}

func login(name: String, password: String) {
if name.isEmpty || password.isEmpty {
view?.showError(text: "fill input")
return
}

authInteractor.login(name: name, password: password, completion: { [weak self] result in
switch result {
case .failure(let error):
self?.view?.showError(text: "\(error)")
case .success(let userId):
self?.loginSuccessCallback?(userId)
}
})
}
}

class LoginViewController: UIViewController, LoginView {
var presenter: LoginPresenter!
...
func showError(text: String) {
showAlert(title: "Error", message: text)
}

private func tapOnLoginButton() {
presenter.login(name: nameTextField.text ?? "", password: passwordTextField.text ?? "")
}
}

protocol AuthInteractor: class {
func login(name: String, password: String, completion: (Result) -> Void)
}

class AuthInteractorImpl: AuthInteractor {
func login(name: String, password: String, completion: (Result) -> Void) {
...
}
}
```
As you can see, the dependency description code takes a small part, and the application code doen't know about how dependencies are implemented.

Also your can show samples:
* [For habr](Samples/SampleHabr/)
* [Chaos](Samples/SampleChaos/)
* [Delegate and observer](Samples/SampleDelegateAndObserver/)
* [SwiftPM big clean architecture](https://github.com/ivlevAstef/FunCorpSteamApp)

Also your can read articles:
* Ru! [https://habr.com/ru/post/457188/](https://habr.com/ru/post/457188/)
* Ru! Old! [https://habr.com/ru/post/311334/](https://habr.com/ru/post/311334/)

## Requirements
iOS 11.0+,macOS 10.13+,tvOS 11.0+, watchOS 4.0+, Linux; ARC

* Swift 5.5-5.9: Xcode 13,14,15; version >= 3.6.3
* Swift 5.0-5.3: Xcode 10.2-12.x; version >= 3.6.3
* Swift 4.2: Xcode 10; version >= 3.4.3
* Swift 4.1: Xcode 9.3; version >= 3.2.3
* Swift 4.0: Xcode 9.0; version >= 3.0.5
* Swift 3.0-3.2: Xcode 8.0-9.0; 0.9.5 <= version < 3.7.0
* Swift 2.3: Xcode 7.0; version < 0.9.5

## Changelog
See [CHANGELOG](CHANGELOG.md) file or [releases](https://github.com/ivlevAstef/DITranquillity/releases).

## History and Plans
- [x] v1.x.x - Started
- [x] v2.x.x - Stabilization
- [x] v3.x.x - Evolution and Features
- [ ] v4.x.x - Graph API and Optimization. Also Documentation and Marketing
- [ ] v5.x.x - Pre compile time validation

## Feedback

### I've found a bug, or have a feature request
Please raise a [GitHub issue](https://github.com/ivlevAstef/DITranquillity/issues).

### I've found a defect in documentation, or thought up how to improve it
Please help library development and create [pull requests](https://github.com/ivlevAstef/DITranquillity/pulls)

### Plea
If you like my library, then support the library by putting star.

### Question?
You can feel free to ask the question at e-mail: [email protected].