在同步代码里调用 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
相关推荐
Swift社区5 天前
LeetCode 391 完美矩形 - Swift 题解
算法·leetcode·swift
升讯威在线客服系统6 天前
从 GC 抖动到稳定低延迟:在升讯威客服系统中实践 Span 与 Memory 的高性能优化
java·javascript·python·算法·性能优化·php·swift
Swift社区6 天前
LeetCode 390 消除游戏 - Swift 题解
leetcode·游戏·swift
东坡肘子7 天前
春晚、机器人、AI 与 LLM -- 肘子的 Swift 周报 #124
人工智能·swiftui·swift
BatmanWayne10 天前
swift-微调补充
人工智能·swift
疯笔码良14 天前
【swiftUI】实现自定义的底部TabBar组件
ios·swiftui·swift
东坡肘子15 天前
祝大家马年新春快乐! -- 肘子的 Swift 周报 #123
人工智能·swiftui·swift
BatmanWayne15 天前
swift微调记录
微调·swift
追夢秋陽15 天前
Cocoa 使用NSCollectionView显示列表,数据不足布局异常处理
macos·objective-c·cocoa·swift·collectionview
新缸中之脑16 天前
SaaS 大灭绝
开发语言·ios·swift