【Swift响应式】【一】Task & await常见用法

1,496 阅读3分钟

在 Swift 中,Taskawait 是用于异步编程的重要工具。它们基于 Swift 的 并发模型 (Concurrency Model) ,允许开发者在异步操作时提高代码的可读性,同时利用多核性能优化任务调度。


1. 基本用法

创建一个 Task 并使用 await

Task 允许在非异步(同步)环境中运行异步代码,而 await 用于等待异步任务的完成。

swift
复制编辑
import Foundation

func fetchData() async -> String {
    try? await Task.sleep(nanoseconds: 2_000_000_000) // 模拟网络延迟 2 秒
    return "Fetched Data"
}

Task {
    let result = await fetchData()
    print(result)
}

2. async 函数调用

Task 内部调用 await

如果 fetchData() 是一个异步函数 (async),它可以在 Task 内部直接 await

swift
复制编辑
Task {
    let data = await fetchData()
    print("Data received: (data)")
}

3. async let 并行执行多个异步任务

async let 允许同时运行多个异步任务,并在所有任务完成后再获取结果。

swift
复制编辑
Task {
    async let data1 = fetchData()
    async let data2 = fetchData()
    
    let result1 = await data1
    let result2 = await data2

    print("Results: (result1), (result2)")
}

这样,fetchData() 会并行执行,而不是按顺序等待执行,提高了效率。


4. Task.sleep 让任务暂停

模拟延迟操作

Task.sleep(nanoseconds:) 用于暂停当前任务。

swift
复制编辑
Task {
    print("Start")
    try? await Task.sleep(nanoseconds: 3_000_000_000) // 3秒
    print("After 3 seconds delay")
}

5. Task.detached 生成独立任务

Task.detached 创建与当前执行环境分离的任务,适用于需要后台运行的任务。

swift
复制编辑
Task.detached {
    let data = await fetchData()
    print("Detached Task Data: (data)")
}

区别

  • 普通 Task {} 继承当前的 Task 优先级和 actor 执行上下文。
  • Task.detached {} 运行在独立上下文中,不继承优先级。

6. Task.cancel() 取消任务

Task 支持取消操作,适用于需要手动停止正在执行的任务的场景。

swift
复制编辑
var task: Task<Void, Never>? = Task {
    for i in 1...10 {
        if Task.isCancelled {
            print("Task was cancelled")
            return
        }
        print("Processing (i)")
        try? await Task.sleep(nanoseconds: 1_000_000_000) // 1 秒
    }
}

DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    task?.cancel() // 3秒后取消任务
}

7. TaskGroup 处理多个异步任务

TaskGroup 用于动态创建多个任务并收集它们的结果。

swift
复制编辑
import Foundation

func fetchMultipleData() async {
    await withTaskGroup(of: String.self) { group in
        for i in 1...3 {
            group.addTask {
                return await fetchData()
            }
        }
        
        for await result in group {
            print("Fetched: (result)")
        }
    }
}

Task {
    await fetchMultipleData()
}

8. @MainActor 确保 UI 线程更新

在 SwiftUI 或 UIKit 开发中,异步任务可能需要更新 UI,这时 @MainActor 保证代码在主线程执行。

swift
复制编辑
import SwiftUI

@MainActor
func updateUI() {
    print("UI Updated on Main Thread")
}

Task {
    await updateUI()
}

9. TaskResult 处理错误

TaskResult 允许获取任务的返回值或错误。

swift
复制编辑
Task {
    let task = Task { () -> String in
        throw NSError(domain: "Example", code: 1, userInfo: nil)
    }

    let result = await task.result
    
    switch result {
    case .success(let value):
        print("Success: (value)")
    case .failure(let error):
        print("Error: (error.localizedDescription)")
    }
}

10. asyncawait 结合 try 处理错误

可以使用 try 处理异步任务的错误。

swift
复制编辑
func fetchDataWithError() async throws -> String {
    throw NSError(domain: "Example", code: 1, userInfo: nil)
}

Task {
    do {
        let data = try await fetchDataWithError()
        print(data)
    } catch {
        print("Error occurred: (error)")
    }
}

11. 结合 URLSession 进行网络请求

Taskawait 适用于网络请求,简化 URLSession 代码。

swift
复制编辑
import Foundation

func fetchJSON() async throws -> [String: Any]? {
    let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONSerialization.jsonObject(with: data) as? [String: Any]
}

Task {
    do {
        if let json = try await fetchJSON() {
            print(json)
        }
    } catch {
        print("Failed to fetch JSON: (error)")
    }
}

12. 结合 Actors 处理并发

Actor 允许安全地在多个 Task 之间共享状态,防止数据竞争。

swift
复制编辑
actor Counter {
    private var count = 0

    func increment() {
        count += 1
    }

    func getCount() -> Int {
        return count
    }
}

let counter = Counter()

Task {
    await counter.increment()
    print(await counter.getCount())
}

总结

用法说明
Task {}在同步环境中运行异步任务
await等待异步任务完成
async let并行执行多个异步任务
Task.sleep(nanoseconds:)任务暂停
Task.detached {}创建独立任务
Task.cancel()取消任务
TaskGroup处理多个动态任务
@MainActor确保 UI 线程更新
Task.result获取任务返回值或错误
try await处理错误
URLSession + await进行网络请求
Actors线程安全的状态管理

这些示例涵盖了 Taskawait 在 Swift 中的主要应用场景,希望能帮助你掌握 Swift 并发编程