在同步代码里调用 async/await:Task 就是你的“任意门”

场景:同步上下文想调异步函数

swift 复制代码
func fetchData() async -> String { /* 网络请求 */ }

struct ContentView: View {
    var body: some View {
        Button("Load") {
            await fetchData()   // ❌ 编译错误:同步闭包里不能用 await
        }
    }
}

错误提示:

Cannot pass function of type '() async -> Void' to parameter expecting synchronous function type

官方逃生舱:包一层 Task {}

swift 复制代码
Button("Load") {
    Task {                      // ✅ 立即启动异步任务
        let data = await fetchData()
        print(data)
    }
}
  • Task 会立刻在新协程里执行闭包,不要求外部上下文支持并发。
  • 无需手动持有 Task 实例,除非你想取消或等待它完成。

Task 的 3 种常见"同步→异步"桥梁模式

模式 代码片段 用途
Fire-and-forget Task { await work() } 按钮点击、日志上报
取消友好 Task { [weak self] in ... } ViewController/View 生命周期
Delegate/App 生命周期 Task { await requestPermissions() } application(_:didFinishLaunchingWithOptions:)

实战 1:带取消的 SwiftUI 任务

swift 复制代码
struct ContentView: View {
    @State private var task: Task<Void, Never>?   // 1️⃣ 持有任务
    
    var body: some View {
        VStack {
            Button("Start") {
                task = Task {                     // 2️⃣ 创建并保存
                    let data = await fetchData()
                    print(data)
                }
            }
            Button("Cancel") {
                task?.cancel()                    // 3️⃣ 外部取消
                task = nil
            }
        }
        .onDisappear {
            task?.cancel()                        // 4️⃣ 生命周期清理
        }
    }
}

记住:视图消失时必须取消,否则后台任务可能访问已销毁的 @State

实战 2:AppDelegate 里请求推送权限

swift 复制代码
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        // 同步方法内直接启动异步任务
        Task {
            do {
                try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound])
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            } catch {
                print("权限请求失败: \(error)")
            }
        }
        
        return true
    }
}
  • Task 让"老派"的同步生命周期钩子也能享受结构化并发。
  • 不需要 awaitapplication(_:didFinishLaunchingWithOptions:) 返回值里,启动即忘即可。

闭包捕获注意事项

swift 复制代码
Button("Load") {
    Task { [weak self] in          // ✅ 防止循环引用
        guard let self else { return }
        self.model.data = await self.fetchData()
    }
}

在 View/ViewController/ViewModel 里使用 Task 时,养成 [weak self] 习惯,避免闭包持有整个视图层级。

一句话总结

"同步上下文想 await?包一层 Task {} 就行。"

它是 Swift 结构化并发的任意门:轻量、无样板、可取消。

只要记得生命周期对齐 + 弱引用捕获,就能在按钮、Delegate、App 生命周期里放心使用 async/await。

参考资料

  1. How to use async/await in synchronous Swift code with tasks
相关推荐
Dream_Ji2 天前
Swift入门(二 - 基本运算符)
服务器·ssh·swift
HarderCoder3 天前
Swift 6.1 `withTaskGroup` & `withThrowingTaskGroup` 新语法导读
ios·swift
HarderCoder3 天前
Swift 并发:Actor、isolated、nonisolated 完全导读
ios·swift
用户094 天前
Swift Feature Flags:功能切换的应用价值
面试·swiftui·swift
HarderCoder4 天前
Swift 5.9 `consume` 操作符:一次说清楚“手动结束变量生命周期”
swift
YungFan4 天前
iOS26适配指南之UIScrollView
ios·swift
HarderCoder4 天前
SwiftUI Preferences 完全指南:从“向上传值”到 Swift 6 并发安全
swiftui·swift
东坡肘子4 天前
苹果正在为系统级支持 MCP 做准备 | 肘子的 Swift 周报 #0104
swiftui·swift·apple
Dream_Ji5 天前
Swift 入门(一 - 基础语法)
开发语言·ios·swift
HarderCoder5 天前
async let 也能调度同步函数?——Swift 并发隐藏小技巧详解
swiftui·swift