在同步代码里调用 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
相关推荐
用户79457223954131 小时前
【AFNetworking】OC 时代网络请求事实标准,Alamofire 的前身
objective-c·swift
报错小能手3 小时前
SwiftUI 框架 认识 SwiftUI 视图结构 + 布局
ui·ios·swift
东坡肘子4 小时前
被 Vibe 摧毁的版权壁垒,与开发者的新护城河 -- 肘子的 Swift 周报 #131
人工智能·swiftui·swift
报错小能手19 小时前
ios开发方向——swift错误处理:do/try/catch、Result、throws
开发语言·学习·ios·swift
小夏子_riotous21 小时前
openstack的使用——5. Swift服务的基本使用
linux·运维·开发语言·分布式·云计算·openstack·swift
mCell1 天前
MacOS 下实现 AI 操控电脑(Computer Use)的思考
macos·agent·swift
用户79457223954131 天前
【DGCharts】iOS 图表渲染事实标准——8 种图表类型、高度可定制,3 行代码画出一条折线
swiftui·swift
chaoguo12342 天前
Any metadata 的内存布局
swift·metadata·value witness table
tangweiguo030519873 天前
SwiftUI布局完全指南:从入门到精通
ios·swift
用户79457223954133 天前
【RxSwift】Swift 版 ReactiveX,响应式编程优雅处理异步事件流
swift·rxswift