Swift中Kotlin suspendCancellableCoroutine等效实现及优化问询
Swift 封装 NotificationCenter 回调为异步函数的最优方案
核心思路
要把NotificationCenter这类系统回调封装成异步函数,同时在任务取消、错误或正常完成时自动清理监听器,无需依赖额外带deinit的包装类,根据iOS版本兼容需求,有两种主流实现方案。
方案一:iOS 13+ 首选(Combine + AsyncSequence)
利用Combine框架将NotificationCenter监听转为异步序列,代码最简洁,且自动处理监听器生命周期:
import UIKit import Combine @MainActor func waitForLifecycleEvent(_ targetState: UIApplication.State = .active) async throws { let notificationName: Notification.Name switch targetState { case .active: notificationName = UIApplication.didBecomeActiveNotification case .inactive: notificationName = UIApplication.willResignActiveNotification case .background: notificationName = UIApplication.didEnterBackgroundNotification @unknown default: throw NSError(domain: "LifecycleEventError", code: -1, userInfo: [NSLocalizedDescriptionKey: "不支持的应用状态"]) } // 监听指定通知,过滤出状态匹配的事件 let notificationSequence = NotificationCenter.default.notifications(named: notificationName) .filter { _ in UIApplication.shared.applicationState == targetState } // 等待第一个符合条件的通知 for await _ in notificationSequence { return } }
优势
- 无需手动管理监听器,Task取消或正常完成时,异步序列会自动终止监听
- 代码简洁,Combine框架已封装所有生命周期逻辑
- 自带状态过滤,避免收到通知但实际状态不符的无效触发
方案二:兼容iOS 12及以下(手动管理监听器)
如果需要兼容低版本,结合withCheckedThrowingContinuation和continuation.onTermination统一处理清理逻辑:
import UIKit @MainActor func waitForLifecycleEvent(_ targetState: UIApplication.State = .active) async throws { let notificationName: Notification.Name switch targetState { case .active: notificationName = UIApplication.didBecomeActiveNotification case .inactive: notificationName = UIApplication.willResignActiveNotification case .background: notificationName = UIApplication.didEnterBackgroundNotification @unknown default: throw NSError(domain: "LifecycleEventError", code: -1, userInfo: [NSLocalizedDescriptionKey: "不支持的应用状态"]) } try await withCheckedThrowingContinuation { continuation in // 创建监听器 let observer = NotificationCenter.default.addObserver( forName: notificationName, object: nil, queue: .main ) { _ in guard UIApplication.shared.applicationState == targetState else { return } // 触发回调后恢复异步任务,同时移除监听器 NotificationCenter.default.removeObserver(observer) continuation.resume() } // 统一处理任务终止(取消/完成/错误)时的清理 continuation.onTermination = { _ in NotificationCenter.default.removeObserver(observer) } } }
关键注意点
- 回调触发后必须手动移除监听器,此时
onTermination不会被调用 continuation.onTermination覆盖任务取消、错误抛出等所有终止场景,确保监听器被彻底清理
通用优化点
- 状态校验:增加过滤逻辑,确保只有当前应用状态匹配目标状态时才触发回调,避免无效通知
- 未知状态处理:用
@unknown default捕获未来新增的应用状态,抛出明确错误,避免崩溃 - 主线程约束:标注
@MainActor确保函数在主线程执行,因为UIApplication状态只能在主线程访问 - 错误明确化:自定义错误域和描述,方便调用方快速定位问题
必须注意的问题
- 任务取消处理:调用方需要捕获
CancellationError,因为任务取消时异步函数会抛出该错误 - 内存泄漏:无论用哪种方案,都要确保监听器在任务终止时被移除,Combine方案或
continuation.onTermination能自动处理该逻辑 - 重复调用:多次调用该函数会创建多个独立监听器,每个任务终止时都会自动清理,无需额外处理
内容的提问来源于stack exchange,提问作者Kibotu
相关产品推荐
相关产品推荐

