异步任务工具包 是一个 Swift 软件包,旨在简化可取消异步任务的管理。它为在 SwiftUI 应用程序中处理异步操作提供了可重用的工具和模式。
探索如何在 SwiftUI 中使用此软件包以及它如何简化代码的真实示例
异步任务工具包提供了高效管理异步任务的工具,具有以下功能:
@Published
属性进行实时 UI 更新,或者如果您可以使用 iOS 17 或更高版本,则可以使用 @observable。Async.SingleTask
: 用于管理单个可取消异步任务的视图模型。Async.SingleTask
类简化了单个异步任务的管理。它跟踪任务的结果、错误状态和活动状态,使其非常适合在 SwiftUI 视图中使用。
以下是使用 Async.SingleTask 异步处理输入并生成转换输出的示例。
struct ProcessInputView: View {
@StateObject private var viewModel = Async.SingleTask<Int, Error>()
private var value: String? { viewModel.value }
private var error: String? { viewModel.error?.localizedDescription }
private var isActive: Bool { viewModel.state == .active }
var body: some View {
VStack {
if let value {
Text("Result: \(value)")
} else if let error {
Text("Error: \(error)")
} else if isActive {
ProgressView("Loading...")
} else {
Button("Process Input", action: processInput)
}
}
}
private func processInput() {
viewModel.start(with: 21) { input in
try await performAsyncProcessing(for: input)
}
}
private func performAsyncProcessing(for input: Int) async throws -> Int {
try await Task.sleep(nanoseconds: 1 * 1_000_000_000) // Simulate a 1-second delay
return input * 2
}
}
对于目标为 iOS 17 及更高版本的项目,您可以使用 Async.ObservableSingleTask,它利用新的 @Observable 宏在 SwiftUI 中实现更高效的状态观察。
@available(iOS 17.0, *)
struct ObservableCustomErrorView: View {
@State private var viewModel = Async.ObservableSingleTask<String, CustomError>(errorMapper: customErrorMapper)
var body: some View {
VStack {
if let value = viewModel.value {
Text("Result: \(value)")
} else if let error = viewModel.error {
Text("Error: \(error)")
} else if viewModel.state == .active {
ProgressView("Loading...")
} else {
Button("Fetch Data", action: fetchData)
}
}
}
private func fetchData() {
viewModel.start {
try await performAsyncFetch()
}
}
private func performAsyncFetch() async throws -> String {
// Simulate an error
throw NSError(domain: "Network", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to reach server"])
}
}
enum CustomError: Error {
case networkError(String)
}
let customErrorMapper: Async.ErrorMapper<CustomError> = { error in
return .networkError(error.localizedDescription)
}