Swift并发编程:async/await实战入门教程
大家好,我是掘金上常写iOS入门教程的全栈工程师。最近收到不少读者私信,说想学Swift并发但被各种GCD、OperationQueue绕晕了。其实我当初学的时候也一样——直到Swift 5.5引入了async/await,我才真正理解了“优雅地处理异步任务”是什么意思。
今天这篇教程,我会用最简单的语言+最实用的例子,带你从零掌握Swift并发编程。无论你是刚学完Swift基础语法,还是正在做第一个App项目,都能轻松上手。
一、什么是async/await?它能做什么?
在移动开发中,我们经常要处理“耗时操作”:比如从网络下载数据、读取本地文件、或者执行一个复杂的计算。如果把这些操作放在主线程(也就是UI线程)里直接运行,App就会卡住甚至闪退。
传统做法是用回调(callback)或者闭包来处理异步结果,但代码会一层套一层,形成“回调地狱”。
而async/await就是Swift提供的现代解决方案:它让你用同步的写法写出异步的逻辑,代码清晰、易读、不易出错。
📌 一句话总结:
async/await让异步代码像写普通函数一样简单。
二、环境准备:你需要什么?
在开始前,请确保你的开发环境满足以下条件:
| 项目 | 要求 |
|---|---|
| Xcode版本 | 13.0 或更高(推荐最新稳定版) |
| iOS部署目标 | iOS 15.0 或更高 |
| Swift版本 | 5.5 或更高 |
💡 为什么要求iOS 15+?
因为async/await的核心API(如Task、async let等)是在Swift 5.5中引入的,而Xcode 13才完整支持这些特性。如果你的项目必须支持iOS 14或更低版本,可以使用backport库,但本教程不涉及。
验证方法:新建一个Playground,输入以下代码:
import Foundation
func fetchData() async -> String {
return "Hello, async!"
}
Task {
let result = await fetchData()
print(result)
}
如果能正常编译运行并打印出Hello, async!,说明环境已就绪。
三、核心概念:用最简单的话讲清楚
1. async:标记一个函数是“异步”的
当你在一个函数声明后面加上async,就表示这个函数内部可能需要等待某些操作完成(比如网络请求),调用它时必须用await。
// 异步函数
func downloadBookTitle() async -> String {
// 模拟网络延迟
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒
return "《Swift并发编程实战》"
}
2. await:等待异步函数的结果
只有在async上下文中(比如另一个async函数里,或Task中),你才能使用await。
// 在Task中调用
Task {
let title = await downloadBookTitle()
print("下载完成:", title)
}
3. Task:启动一个异步任务
Task就像是一个“异步容器”,你可以在里面安全地使用await。它会自动在后台线程执行,不会阻塞UI。
✅ 安全意识提醒:
所有网络请求、文件读写等耗时操作,都应放在Task或async函数中,绝不能直接在主线程执行,否则会导致App卡顿甚至被系统杀死。
四、实战项目:做一个“书籍信息爬虫”
现在,我们来做一个小项目:从一个模拟的网络接口获取书籍信息,并展示在控制台。虽然不能真的做“爬虫”(那涉及法律和道德问题),但我们可以模拟一个合法的数据源来练习并发逻辑。
⚠️ 重要声明:
本文中的“爬虫”仅用于教学演示,实际开发中请遵守网站robots.txt协议,使用官方API,并尊重版权。切勿对他人网站进行未授权的数据抓取!
步骤1:定义数据模型
struct Book: Codable {
let id: Int
let title: String
let author: String
}
步骤2:模拟网络请求(替代真实爬虫)
// 模拟从“网络”获取书籍列表
func fetchBooks() async throws -> [Book] {
// 模拟1秒延迟
try await Task.sleep(nanoseconds: 1_000_000_000)
// 返回模拟数据
return [
Book(id: 1, title: "《Swift并发指南》", author: "张三"),
Book(id: 2, title: "《iOS性能优化》", author: "李四"),
Book(id: 3, title: "《现代Swift实践》", author: "王五")
]
}
步骤3:并发获取多本书的详情(进阶用法)
假设每本书还有一个详情接口,我们需要同时获取多本书的详情:
func fetchBookDetail(for id: Int) async throws -> String {
try await Task.sleep(nanoseconds: 500_000_000) // 0.5秒
return "这是第\(id)本书的详细介绍..."
}
// 并发获取所有书籍详情
func fetchAllBookDetails() async throws -> [String] {
let books = try await fetchBooks()
// 使用async let实现并发
async let detail1 = fetchBookDetail(for: books[0].id)
async let detail2 = fetchBookDetail(for: books[1].id)
async let detail3 = fetchBookDetail(for: books[2].id)
// 等待所有结果
return try await [detail1, detail2, detail3]
}
🔍 为什么用
async let?
它能让多个异步操作并行执行,而不是一个接一个地等待。总耗时≈最长的那个任务(0.5秒),而不是三个相加(1.5秒)。
步骤4:在main中运行整个流程
@main
enum BookCrawler {
static func main() async throws {
print("开始获取书籍列表...")
let books = try await fetchBooks()
print("获取到 \(books.count) 本书")
print("开始并发获取详情...")
let details = try await fetchAllBookDetails()
print("获取完成!共 \(details.count) 条详情")
// 打印结果
for (index, book) in books.enumerated() {
print("📚 \(book.title) by \(book.author)")
print(" → \(details[index])\n")
}
}
}
运行后,你会看到类似输出:
开始获取书籍列表...
获取到 3 本书
开始并发获取详情...
获取完成!共 3 条详情
📚 《Swift并发指南》 by 张三
→ 这是第1本书的详细介绍...
📚 《iOS性能优化》 by 李四
→ 这是第2本书的详细介绍...
📚 《现代Swift实践》 by 王五
→ 这是第3本书的详细介绍...
五、新手常见问题解答
Q1:为什么我的await报错“'async' call in a function that does not support concurrency”?
原因:你试图在非async上下文中使用await。
解决:把代码包在Task { }里,或者把当前函数声明为async。
// ❌ 错误
let data = await fetchData()
// ✅ 正确
Task {
let data = await fetchData()
}
Q2:如何在UI中使用async/await?
在UIViewController中,你可以这样更新界面:
class BookViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
Task {
do {
let books = try await fetchBooks()
// 注意:回到主线程更新UI
await MainActor.run {
self.updateUI(with: books)
}
} catch {
print("加载失败:", error)
}
}
}
func updateUI(with books: [Book]) {
// 更新tableView等
}
}
🔒 安全意识重点:
UI操作必须在主线程执行!使用MainActor.run确保线程安全。
Q3:async/await能替代GCD吗?
大部分场景可以。但对于底层线程控制、队列优先级等高级需求,GCD仍有优势。建议:
- 新项目优先用
async/await - 老项目逐步迁移
- 复杂并发逻辑可结合
TaskGroup、Actor等新特性
六、学习建议与下一步
推荐学习路径
- 巩固基础:先掌握
async/await、Task - 进阶并发:学习
TaskGroup(并发循环)、AsyncStream(异步序列) - 线程安全:理解
Actor模型,避免数据竞争 - 实战项目:在真实App中替换旧的回调写法
推荐资源
| 类型 | 名称 | 说明 |
|---|---|---|
| 书籍 | 《Modern Swift Concurrency》 | 英文原版,深度讲解 |
| 官方文档 | Swift Concurrency Guide | 必读 |
| 开源项目 | Async Algorithms | Apple官方库 |
| 教程 | WWDC2021 Session 10132 | “Meet async/await in Swift” |
避坑指南
- ❌ 不要在
async函数中使用DispatchQueue.main.async来更新UI —— 用MainActor - ❌ 不要滥用
Task { }嵌套 —— 尽量保持函数层级扁平 - ✅ 所有异步函数都应考虑错误处理(
throws+do-catch)
结语
async/await是Swift现代化的重要一步,它让并发编程变得直观而安全。我当初花了两周才搞懂GCD的各种队列,而async/await半天就上手了——这就是技术进步的力量。
希望这篇教程能帮你迈出并发编程的第一步。记住:不要怕犯错,多写多试,你很快就能写出高效又安全的异步代码!
如果你觉得有帮助,欢迎在掘金关注我,我会持续更新更多零基础友好的iOS开发教程。下次见!

评论 0