DITranquillity
Tranquillity 是一个轻量级但功能强大的 Swift 依赖注入库。
"Tranquillity"这个名字奠定了该库的基本原则:清晰、简单和安全。
它表示 - 使用这个库,你将会对你的依赖关系感到安心。
关于依赖注入
依赖注入是一种软件设计模式,其中某人向对象提供依赖项。
这是更广泛的控制反转技术的一种形式,有助于实现依赖倒置原则。
我还建议你阅读术语表,这将有助于更好地理解相关术语。
特性
核心
UI
图形 API
安装
该库支持三种流行的包管理器:Cocoapods、Carthage 和 SwiftPM。
CocoaPods
在你的 Podfile
中添加以下行:
pod 'DITranquillity'
SwiftPM
你可以使用 "Xcode/File/Swift Packages/Add Package Dependency..." 并写入 GitHub URL:
https://github.com/ivlevAstef/DITranquillity
你也可以编辑你的 Package.swift
并在 dependencies
部分添加以下行:
.package(url: "https://github.com/ivlevAstef/DITranquillity.git", from: "4.6.0")
不要忘记在你的 target
部分指定依赖行:
.product(name: "DITranquillity")
注意! - SwiftPM 不支持 "UI" 部分的功能。
Carthage
在你的 Cartfile
中添加以下行:
github "ivlevAstef/DITranquillity"
Carthage 支持 "UI" 和 "GraphAPI" 部分,无需额外操作。
使用
该库使用声明式依赖描述风格,允许你将应用程序代码与依赖描述代码分离。
为了快速入门,让我们看一个简化的 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
...
}
// 你可以编写无需强制转换的代码,这里是简化的示例
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; 版本 >= 3.6.3
- Swift 5.0-5.3: Xcode 10.2-12.x; 版本 >= 3.6.3
- Swift 4.2: Xcode 10; 版本 >= 3.4.3
- Swift 4.1: Xcode 9.3; 版本 >= 3.2.3
- Swift 4.0: Xcode 9.0; 版本 >= 3.0.5
- Swift 3.0-3.2: Xcode 8.0-9.0; 0.9.5 <= 版本 < 3.7.0
- Swift 2.3: Xcode 7.0; 版本 < 0.9.5
更新日志
历史和计划
- v1.x.x - 开始
- v2.x.x - 稳定化
- v3.x.x - 发展和功能
- v4.x.x - 图形 API 和优化。同时还有文档和营销
- v5.x.x - 预编译时验证
反馈
我发现了一个bug,或有一个功能请求
请提出一个 GitHub 问题。
我在文档中发现了缺陷,或想到了如何改进
请帮助改进库并创建 pull requests
请求
如果你喜欢我的库,请通过加星来支持这个库。
问题?
你可以随时通过电子邮件 ivlev.stef@gmail.com 提出问题。