-
如何使用
-
async await
- async 用于标记方法为异步方法
- 执行异步方法时需要加上await
- 异步方法执行环境是在一个Task中
- 将一个基于回调(callback)的异步 API 转换为 Swift Concurrency 的 async/await 风格。
- withCheckedThrowingContinuation
- withUnsafeContinuation
func loadImage(from url: URL, completion: @escaping (Result<UIImage, Error>) -> Void) { DispatchQueue.global().asyncAfter(deadline: .now() + 1) { if let image = UIImage(systemName: "bolt") { completion(.success(image)) } else { completion(.failure(NSError(domain: "ImageError", code: 1))) } } } func loadImageAsync(from url: URL) async throws -> UIImage { try await withCheckedThrowingContinuation { continuation in loadImage(from: url) { result in switch result { case .success(let image): continuation.resume(returning: image) case .failure(let error): continuation.resume(throwing: error) } } } }
-
Task
-
最基本的
Task
创建方式func fetchSomething() async -> String { return "Fetched data" } // 启动一个任务 Task { let result = await fetchSomething() print("Result: \(result)") }
-
用
Task
的几种变体-
使用
Task
返回值 & 捕获错误let task = Task { try await fetchData() } do { let data = try await task.value } catch { print("Error: \(error)") }
使用
Task.detached
,Task.detached
会脱离当前上下文,比如不继承@MainActor
, 适合执行不依赖当前 actor 的后台任务
Task.detached { // 独立于当前上下文(如 actor 或 MainActor) let value = await computeInBackground() print(value) }
-
-
使用任务优先级
Task(priority: .userInitiated) { await loadData() } ```
-
-
Task group
- 调用group中的cancelAll方法时,系统会向所有的子任务发送取消信号,通过Task.isCanceled 为 true 可以判断
- 子任务需要正常处理这个取消信号,才会终止任务的执行。
try Task.checkCancellation()
func runAllTasks() async throws { started = Date() try await withThrowingTaskGroup(of: Result<String, Error>.self) { [unowned self] group in let batchSize = 1 for index in 0..<batchSize { group.addTask { await self.worker(number: index) } } // 1 var index = batchSize // 2 for try await result in group { switch result { case .success(let result): print("Completed:\(result))") case .failure(let error): print("Failed: \(error.localizedDescription)") } // 3 if index < total { group.addTask { [index] in await self.worker(number: index) } index += 1 } } await MainActor.run { completed = 0 countPerSecond = 0 scheduled = 0 } } } func worker(number: Int) async -> Result<String, Error> { await onScheduled() let task = ScanTask(input: number) let result: Result<String, Error> do { result = try .success(await task.run()) } catch { result = .failure(error) } await onTaskCompleted() return result } ```
-
AsyncSequence
protocol AsyncSequence { associatedtype Element func makeAsyncIterator() -> AsyncIterator }
- 类似
Sequence
(同步迭代器)但用于异步迭代 - 使用
for await
来异步消费数据流 - Swift 提供了很多 conform 的类型,比如:
URLSession.AsyncBytes
AsyncThrowingStream
AsyncStream
AsyncLazySequence
- 类似
-
AsyncStream
是AsyncSequence的一种实现
-
核心用途: 把一个基于回调或事件推送的数据源,转换成用for await消费的异步序列
func makeTimerStream(interval: TimeInterval) -> AsyncStream<Date> { AsyncStream { continuation in let timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in continuation.yield(Date()) } continuation.onTermination = { @Sendable _ in timer.invalidate() } } } Task { for await time in makeTimerStream(interval: 1) { print("Current time: \(time)") } extension NotificationCenter { func notifications(for name: Notification.Name) -> AsyncStream<Notification> { AsyncStream<Notification>.init { continuation in NotificationCenter.default.addObserver(forName: name, object: nil, queue: nil) { notification in continuation.yield(notification) } } } } }
-
-
Swift并发模型
- Swift 并发模型(Swift Concurrency Model)是 Apple 为 Swift 提供的一套现代并发编程机制,它从语言层面解决了多线程开发中常见的数据竞争、线程爆炸、回调地狱、不易维护等问题。
- 一句话理解:Swift 并发模型是一套基于 async/await、actor、任务调度、隔离机制的编程模型,旨在让并发代码像同步代码一样安全、可读、可维护。
- Swift 并发模型包含哪些核心组成:
-
async/await
简洁地编写异步代码let result = try await fetchData()
-
Task
在并发环境中启动新任务Task { await doSomething() }
-
TaskGroup
ThrowingTaskGroup
并发执行多个任务,并合并结果|并发请求多个接口 -
actor
对象级别的线程隔离,保护状态不被数据竞争actor Counter { var value = 0 }
-
@MainActor
@globalActor
明确指定执行上下文(主线程或其他共享线程)@MainActor class ViewModel {}
-
Sendable
编译期检查跨线程传递的数据是否安全|struct User: Sendable
-
@TaskLocal
提供任务内的线程安全局部变量@TaskLocal static var currentUser
-
-
actor模型
- actor 是线程隔离的并发单元,它的代码默认不在主线程,但所有对其内部状态的访问都是自动串行调度、线程安全的。
- actor 内部状态只能被一个任务访问,避免数据竞争(Data Race)
- actor 并不是“多线程运行”,而是“串行调度在某个线程上(可能是主线程,也可能是后台线程)”
- 作用范围:每个实例隔离
- nonisolated 关键字
- actor中的方法是默认隔离的
- 当方法不需要访问actor中内部状态时,可以加上 nonisolated 不隔离
- nonisolated修饰的方法,要确保线程是安全的。
- nonisolated修饰的方法,节约性能,不需要actor之间跳转
- 隔离的目的是为了确保方法在执行时,访问安全
-
MainActor
- @MainActor 标记的所有的代码都是在主线程中执行,并且线程安全
- Swift 编译器和运行时会保证这些代码在主线程执行
- 所以只要正确使用 @MainActor,就能避免 UI 线程访问错误
- 无需手动跳线程(不需要 DispatchQueue.main.async)
-
globalActor
-
global actor
是全局作用域的 actor,允许你将某类代码指定为“总是由某个共享 actor 串行执行”,以实现线程隔离和一致性调度。所有标记代码共享同一实例, 比如:全局日志、UI、数据库访问等统一上下文。 - 最常见的 global actor 就是:@MainActor
- 为什么需要
global actor
?- 普通
actor
是 实例级别的线程隔离,每个 actor 实例拥有自己的队列。 - 而
global actor
是 全局级别的线程隔离,多个实例共享一个执行上下文(例如主线程)。
- 普通
@globalActor actor Database { static let shared = Database() private var manager: DatabaseManager! func setUp() async { manager = await DatabaseManager() } } @Database class DatabaseManager { init() {} func saveData(_ data: String) async { } }
-