KOInject 2.0.0

KOInject 2.0.0

Kuba Ostrowski 维护。



KOInject 2.0.0

  • 作者
  • Kuba Ostrowski

KOInject

一个简单轻量级的 IoC 容器,支持使用模式和多个参数的注册/解析/销毁模式。它还支持延迟和隔离解析。

特性

  • 支持多个泛型参数的 注册/解析/销毁 模式。
  • 支持 使用范围注册 - 通过将对象与其范围参数一起注册来声明解析对象的生存期。
  • 延迟解析器 - 仅在需要时才对对象进行延迟解析。在需要动态连接而不是持续连接数据库时很有用。
  • 隔离解析器 - 隔离使用解析对象,其中对象在隔离操作的开始时自动解析,并在完成时自动销毁。适用于所有类型的事务。

要求

  • iOS 11.0+ / macOS 10.13+ / tvOS 11.0+ / watchOS 4.0+
  • Xcode 11.0+
  • Swift 5.1

安装

KOInject 不包含任何外部依赖。如果您想保持更新,请通过 Cocoapods 安装 KOInject。

CocoaPods

在 Podfile 的目标中添加以下条目

pod 'KOInject', '~> 2.0'

例如

platform :ios, '11.0'
use_frameworks!

target 'Target Name' do
pod 'KOInject', '~> 2.0'
end

运行以下命令以安装 pods

pod install

Swift Package Manager

点击“文件”->“添加包”->输入KOInject 仓库的 URL,然后点击“添加包”。

您可以在 Package.swift 中手动添加依赖,如下所示

let package = Package(
    name: "SomePackage",
    platforms: [.iOS(.v11)],
    products: [
        .library(
            name: "YourLib",
            targets: ["YourLib"]
        )
    ],
    // here we declare dependency that we want to add
    dependencies: [
        .package(
            url: "https://github.com/Flawion/KOInject.git",
            from: "2.0.0"
        )
    ]
    targets: [
        // target where we use our dependency
        .target(
            name: "YourLib",
            dependencies: ["KOInject"]
        )
    ]
)

手动

您可以使用 KOInject 手动并按您的喜好进行更改。这是做这件事的简单方法之一。

  1. 下载仓库。
  2. 将 KOInject.xcodeproj 和 Sources 文件夹复制到您的项目目录中。
  3. 在项目浏览器中点击“向 'Your project' 添加文件”->选择 KOInject.xcodeproj. Xcode 将自动将 KOInject 添加为子项目。
  4. 在项目设置->目标->添加嵌入库->选择 Workspace->KOInject->KOInject.framework.
  5. 如果您不希望每次改动后都手动构建KOInject,您可以前往“构建阶段”->“依赖项”->“添加”->“选择工作区”->“KOInject”->“KOInject.framework”。

用法

您需要在计划使用该框架的文件顶部添加以下导入。

import KOInject

注册/解析/销毁

  1. 首先注册您稍后要解析的依赖项。
let container = KOIContainer()
container.register(type: ApiClientProtocol.self) { _ in
    ApiClient()
}
container.register(type: DataStorageProtocol.self) { _ in
    DataStorage()
}

您可以添加多个参数,注册可以看起来像这样。

container.register(type: DataStorageProtocol.self) { _, rootPath, clearOnDispose in
    DataStorage(rootPath: rootPath, clearOnDispose: clearOnDispose)
}

第一个参数是KOIResolverProtocol类型,因此您可以解析其他所需的依赖项来创建新的对象。

container.register(type: GameDetailsViewModelProtocol.self, scope: .separate) { (resolver, game: GameModel) in
    GameDetailsViewModel(apiClient: resolver.resolve()!, game: game)
}
container.register(type: GameDetailsViewControllerProtocol.self, scope: .separate) { (resolver, game: GameModel) in
    GameDetailsViewController(viewModel: resolver.resolve(arg1: game)!)
}
  1. 解析依赖项
struct GameModel {
    let uuid: String
    let name: String
}
// ...
let game = GameModel(uuid: "123-123-123", name: "TestGame")
let gameDetailsViewController: GameDetailsViewControllerProtocol? = container.resolve(arg1: game)
  1. 当您不再需要时,请销毁注册数据。
container.dispose()

按作用域注册

在注册类型时,您可以传递额外的作用域参数,这将确定解析对象的生存期。

  1. shared - 默认作用域。对象将在首次解析时创建一次。在下一次解析调用中,将使用相同的对象。
protocol ObjectIdentifiableProtocol {
    var id: String { get }
}

final class ObjectIdentifiable: ObjectIdentifiableProtocol, Identifiable {
    let id: String = UUID().uuidString
}
// ...

container.register(type: ObjectIdentifiableProtocol.self) { _ in
    ObjectIdentifiable()
}
let object: ObjectIdentifiableProtocol? = container.resolve()
let object2: ObjectIdentifiableProtocol? = container.resolve()
print(object?.id == object2?.id) // prints true
  1. weakShared - 类似于shared,但当没有强引用时,对象将被删除。
container.register(type: ObjectIdentifiableProtocol.self, scope: .weakShared) { _ in
    ObjectIdentifiable()
}
var object: ObjectIdentifiableProtocol? = container.resolve()
let objectId = object?.id
var object2: ObjectIdentifiableProtocol? = container.resolve()
let objectId2 = object2?.id
print(objectId == objectId2) // prints true

// remove strong's references
object = nil
object2 = nil

// resolve new object
let object3: ObjectIdentifiableProtocol? = container.resolve()
let objectId3 = object3?.id
print(objectId == objectId3) // prints false
  1. separate - 每次解析都会返回新的对象。
container.register(type: ObjectIdentifiableProtocol.self, scope: .separate) { _ in
    ObjectIdentifiable()
}
let object: ObjectIdentifiableProtocol? = container.resolve()
let object2: ObjectIdentifiableProtocol? = container.resolve()
print(object?.id == object2?.id) // prints false

懒解析

在某些情况下,我们不想让对象持续有效。注入打开的数据流连接不是最佳解决方案。因此,我们可以使用延迟解析器。

// register dependencies
let container = KOIContainer()
container.register(type: DataBaseClientProtocol.self) { (_, rootPath: String) in
    DataBaseClient(rootPath: rootPath)
}
container.register(type: ViewModelProtocol.self, scope: .separate) { (resolver, rootPath: String) in
    let dataBaseLazyResolver = KOILazyResolverArg1(resolver: resolver, type: DataBaseClientProtocol.self, arg1: rootPath) // create lazy Resolver
    return ViewModel(dataBaseLazyResolver: dataBaseLazyResolver) // inject it!
}
// ...

final class ViewModel: ViewModelProtocol {
    let dataBaseLazyResolver: KOILazyResolverArg1<DataBaseClientProtocol, String>
    
    init(dataBaseLazyResolver: KOILazyResolverArg1<DataBaseClientProtocol, String>) {
        self.dataBaseLazyResolver = dataBaseLazyResolver
    }
    
    // ...
    func append(data: Data) {
        dataBaseLazyResolver.resolve() // resolve object
        dataBaseLazyResolver.object!.append(data: data) // use it
        dataBaseLazyResolver.dispose() // dispose it
    }
}

隔离解析器

当我们使用事务操作时,我们应该对它们的访问权限非常有限。使用隔离解析器,你只能在隔离的操作中使用解析过的对象。隔离解析器是延迟解析器的一种适配器。

// register dependencies
let container = KOIContainer()
container.register(type: UserBillingProtocol.self, scope: .weakShared) { (_, userId: String) in
    UserBilling(userId: userId)
}
container.register(type: ViewModelProtocol.self, scope: .separate) { (resolver, userId: String) in
    // create lazy and isolated resolvers
    let lazyResolver = KOILazyResolverArg1(resolver: resolver, type: UserBillingProtocol.self, arg1: userId)
    let isolatedResolver = KOIIsolatedResolver(lazyResolver: lazyResolver)
    return ViewModel(userBillingIsolatedResolver: isolatedResolver)
}
// ...

final class ViewModel: ViewModelProtocol {
    let userBillingIsolatedResolver: KOIIsolatedResolver<UserBillingProtocol>
    
    init(userBillingIsolatedResolver: KOIIsolatedResolver<UserBillingProtocol>) {
        self.userBillingIsolatedResolver = userBillingIsolatedResolver
    }
    
    // ...
    func add(payment: Payment) {
        // resolve object in isolated action
        userBillingIsolatedResolver.resolve { userBilling in
            userBilling?.add(payment: payment)
        }
    }
}

许可证

该项目受MIT许可证的许可 - 有关详细信息,请参阅LICENSE文件。