在 Swift 中,Task 和 await 是用于异步编程的重要工具。它们基于 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. Task 与 Result 处理错误
Task 的 Result 允许获取任务的返回值或错误。
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. async 和 await 结合 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 进行网络请求
Task 和 await 适用于网络请求,简化 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 | 线程安全的状态管理 |
这些示例涵盖了 Task 和 await 在 Swift 中的主要应用场景,希望能帮助你掌握 Swift 并发编程