异步任务工具包

如果您认为继续开发此软件包是有价值的,请给仓库点赞。这将帮助我了解哪个软件包值得投入更多精力。

异步任务工具包 是一个 Swift 软件包,旨在简化可取消异步任务的管理。它为在 SwiftUI 应用程序中处理异步操作提供了可重用的工具和模式。

SwiftUI 示例

探索如何在 SwiftUI 中使用此软件包以及它如何简化代码的真实示例

  1. 异步定位
  2. Replicate Kit
  3. OpenAI 异步图像

概述

异步任务工具包提供了高效管理异步任务的工具,具有以下功能:

用法

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
    }
}

Async.ObservableSingleTask

对于目标为 iOS 17 及更高版本的项目,您可以使用 Async.ObservableSingleTask,它利用新的 @Observable 宏在 SwiftUI 中实现更高效的状态观察。

示例:使用 ObservableSingleTask 获取没有输入的数据

@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)
    }