Skip to content

Latest commit

 

History

History
236 lines (190 loc) · 12 KB

README_ru.md

File metadata and controls

236 lines (190 loc) · 12 KB

Tranquillity

# DITranquillity Спокойствие это простая, но мощная библиотека на языке swift для [внедрения зависимостей](https://ru.wikipedia.org/wiki/Внедрение_зависимости).

Название "Спокойствие" выбрано не случайно - оно закладывает три базовых принципа библиотеки: понятность, простота и безопасность.

Оно говорит - используйте библиотеку и вы будете спокойны за свои зависимости.

Сменить язык: English, Russian

Что такое внедрение зависимостей?

Внедрение зависимостей (DI) это паттерн проектирования при котором некто поставляет зависимости в объект.

Является специфичной формой принципа инверсии управления (IoC) и помощником для принципа инверсии зависимостей.

Более подробно об этом можно почитать по ссылке

И советую ознакомиться со словарем который поможет лучше ориентироваться в терминах.

Возможности

Ядро

UI

Graph API

Установка

Библиотека поддерживает три популярных пакетных менеджера: Cocoapods, Carthage, SwiftPM.

CocoaPods

Добавьте строчку в ваш Podfile:

pod 'DITranquillity'

SwiftPM

Вы можете воспользуйтесь "Xcode/File/Swift Packages/Add Package Dependency..." и указать в качестве url:

https://github.com/ivlevAstef/DITranquillity

Или прописать в вашем Package.swift файле в секции dependencies:

.package(url: "https://github.com/ivlevAstef/DITranquillity.git", from: "4.6.0")

И не забудьте указать в таргете в аргументе dependencies зависимость на библиотеку:

.product(name: "DITranquillity")

Важно! - SwiftPM не поддерживает фичи из секции UI.

Carthage

Добавьте строчку в ваш Cartfile:

github "ivlevAstef/DITranquillity"

Carthage поддерживает работу со сторибоардами графом и прямое внедрение, без дополнительных действий.

Использование

Библиотека использует декларативный стиль описания зависимостей, и позволяет отделить ваш прикладной код от кода описания зависимостей.

Для быстрого входа давайте рассмотрим пример кода одного упрощенного VIPER экрана:

.................................................
/// Описание зависимостей

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)

.................................................
/// Место запуска приложения

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

.................................................
/// Код приложения

import SwiftLazy

class LoginRouter {
    let rootViewController = UINavigationController()
    private let loginPresenterProvider: Provider<LoginPresenter>
    
    init(loginPresenterProvider: Provider<LoginPresenter>) {
        loginPresenterProvider = loginPresenterProvider
    }
    
    func start() {
        let presenter = loginPresenterProvider.value
        presenter.loginSuccessCallback = { [weak self] _ in
            ...
        }
        // без force cast можно обойтись, но этот вопрос выходит за рамки разбора DI
        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<String, Error>) -> Void)
}

class AuthInteractorImpl: AuthInteractor {
    func login(name: String, password: String, completion: (Result<String, Error>) -> Void) {
        ...
    }
}

Как видим код описывающий внедрение зависимостей занимает малую часть, а прикладной код остается в неведенье о способе внедрения зависимостей.

Для рассмотрения более сложных кейсов советую посмотреть примеры кода:

Или прочитать статьи:

Требования

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.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 файл, или вкладку releases.

История и планы

Обратная связь

Я нашел баг, или хочу больше возможностей

Напишите задачу на вкладке GitHub задачи.

Я нашел проблему в документации, или я знаю как улучшить библиотеку

Вы можете помочь развитию библиотеки сделав pull requests

Просьба

Если вам понравилась моя библиотека, то поддержите библиотеку поставив звёздочку.

Остались вопросы?

Я могу ответить на ваши вопросы по почте: [email protected]