Swift中如何同步工作任务与进度视图控制器的展示、销毁流程
解决方案
方案1:CheckedContinuation封装异步present(兼容性最优,iOS 15+支持)
通过withCheckedContinuation将UIKit的回调式API转为async/await风格,再用async let同时执行弹窗弹出和查询任务,自动等待两个任务全部完成后再执行后续逻辑,不需要硬编码超时时间,符合Swift Concurrency设计规范。
首先扩展UIViewController:
extension UIViewController { @MainActor func present(_ viewController: UIViewController, animated: Bool) async { await withCheckedContinuation { continuation in present(viewController, animated: animated) { continuation.resume() } } } }
使用示例:
let progressController = UIAlertController(title: "Progress", message: nil, preferredStyle: .alert) // 同时启动两个异步任务,互不阻塞 async let presentFinish: () = self.present(progressController, animated: true) async let queryFinish: () = yourQueryTask() // 替换为你的实际耗时查询异步方法 // 等待两个任务全部完成 _ = await [presentFinish, queryFinish] // 执行后续逻辑 progressController.dismiss(animated: true) { // 弹出结果视图控制器 }
方案2:AsyncSemaphore(iOS 16+,适配二元信号量使用习惯)
如果你更熟悉信号量的同步逻辑,可以使用Swift Concurrency原生的AsyncSemaphore实现二元信号量效果,不会阻塞线程,写法和GCD信号量高度一致:
// 初始化信号量为0 let presentSemaphore = AsyncSemaphore(value: 0) let controller = UIAlertController(title: "Progress", message: nil, preferredStyle: .alert) // present完成时发送信号 self.present(controller, animated: true, completion: { presentSemaphore.signal() }) Task { @MainActor in // 执行耗时查询任务 try await Task.sleep(nanoseconds: 10_000_000) // 等待present完成的信号 await presentSemaphore.wait() // 执行后续逻辑 controller.dismiss(animated: true) // 弹出结果视图控制器 }
注意事项
- 所有UI相关操作需要在主Actor执行,示例中已经添加
@MainActor修饰避免线程异常。 - 两种方案都不需要硬编码超时时间,完全依赖系统回调触发同步,稳定性远高于原有的固定时长sleep方案。
内容的提问来源于stack exchange,提问作者Jimmie
相关产品推荐
相关产品推荐

