SwiftUseCase 是一个用于创建独立且可测试覆盖的用例库,并具有强大的执行 API。
您可以使用 Swift Package Manager 来集成该库,方法是在您的 Package.swift 文件中添加以下依赖项,或直接在 Xcode 中添加
.package(url: "https://github.com/xtro/SwiftUseCase.git", .upToNextMajor(from: "0.0.1"))
一个 UseCase 是一个简单的容器,包含一个 Parameter
和 Result
类型,并执行一个 Execution
。
public protocol UseCaseable {
associatedtype Parameter: Sendable
associatedtype Result: Sendable
associatedtype Execution: Sendable
var execute: Execution { get }
}
共有四种类型的执行
public typealias Executable<Parameter: Sendable, Result: Sendable> = @Sendable (Parameter) -> Result
public typealias AsyncExecutable<Parameter: Sendable, Result: Sendable> = @Sendable (Parameter) async -> Result
public typealias ThrowingExecutable<Parameter: Sendable, Result: Sendable> = @Sendable (Parameter) throws -> Result
public typealias AsyncThrowingExecutable<Parameter: Sendable, Result: Sendable> = @Sendable (Parameter) async throws -> Result
在这个例子中,我们使用 swift concurrency 实现了一个数据任务。参数是 URLRequest 和 URLSession
import SwiftUseCase
public enum Network {
public struct DataTask: AsyncThrowingUseCase {
public struct Parameter {
let request: URLRequest
let session: URLSession
}
public typealias Result = (response: HTTPURLResponse, data: Data)
public var execute: AsyncThrowingExecutable<Parameter, Result> = { parameter in
class CancellableWrapper {
var dataTask: URLSessionDataTask?
}
let urlSessionTask = CancellableWrapper()
return try await withTaskCancellationHandler {
return try await withUnsafeThrowingContinuation { continuation in
urlSessionTask.dataTask = parameter.session.dataTask(with: parameter.request) { data, response, error in
if let error = error {
continuation.resume(throwing: error)
}
if let data = data {
let result = (response as! HTTPURLResponse, data)
continuation.resume(returning: result)
}
}
urlSessionTask.dataTask?.resume()
}
} onCancel: {
urlSessionTask.dataTask?.cancel()
}
}
}
}
之后,我们可以通过多种方式使用已实现的代码。
用作 Combine 发布者
let usecase = Network.DataTask()
usecase.publisher(
.init(
request: URLRequest(url: URL(string: path)!),
session: session ?? .shared
)
)
看起来不错,但在这种情况下,参数和初始化太复杂了,我们可以通过编写像这样的扩展来简化它
extension Network.DataTask.Parameter {
static func get(_ path: String, session: URLSession? = nil) -> Self {
.init(
request: URLRequest(url: URL(string: path)!),
session: session ?? .shared
)
}
}
extension Network {
static var dataTask: DataTask {
DataTask()
}
}
好多了,现在我们可以用作 Combine 发布者
Network.dataTask
.publisher( .get("https://api.coincap.io/v2/assets") )
...
或使用 blocks
Network.dataTask( .get("https://api.coincap.io/v2/assets") ) { result in
...
}
或在 swift concurrency 中
let result = try await Network.dataTask( .get("https://api.coincap.io/v2/assets") )
最后,每个 UseCase 都可以转换为 AnyUseCase
,这是一种用例的类型擦除表示
let usecase = MyUseCase().eraseToAnyUseCase
usecase.onComplete = {
print("Result: \($0)")
}
usecase.onFailure = {
print("Failure: \($0)")
}
usecase(parameter)
SwiftUseCase 是一个 MIT 许可的开源项目,其持续开发完全由出色的支持者的支持成为可能。如果您想加入他们,请考虑赞助此开发。
欢迎提交 Pull Request。对于重大更改,请先打开一个 issue 讨论您想要更改的内容。
请确保根据需要更新测试。
此库根据 MIT 许可证发布。有关详细信息,请参阅 LICENSE。