Swift 6中基于Timer的API管理器如何规避回调的@Sendable要求
Swift 6中基于Timer的API管理器如何规避回调的@Sendable要求
我太懂这种升级Swift 6时被@Sendable要求卡壳的感觉了——尤其是你的API管理器已经依赖Timer触发回调,还要改一堆非Sendable的回调类型,完全重构实在太折腾。针对你的场景,有几个不用大改架构就能解决的办法:
1. 把回调调度到MainActor执行(最安全的方案)
Swift 6对@Sendable的要求核心是线程安全,而Timer的闭包默认在主线程的RunLoop上执行。你可以把回调的执行包裹到@MainActor的上下文里,这样既符合线程安全要求,又不用修改回调的类型标注。
修改后的代码示例:
func performRequest<T: Decodable>( request: T, onSuccess: @escaping (T) -> Void, onFailure: @escaping (Error) -> Void, onOffline: (() -> Void)? = nil ) { Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in // 用MainActor包裹回调执行,规避Sendable检查 Task { @MainActor in if someCondition { onSuccess(someResult) } else { onFailure(someError) } // 记得根据业务逻辑停止定时器 if shouldStopTimer { timer.invalidate() } } } }
这个方案的好处是完全符合Swift 6的并发安全规则,不需要任何“不安全”的标记,适合大多数场景。
2. 用@unchecked Sendable标记回调(最快的临时方案)
如果你能确保所有回调只会在同一个线程(比如主线程)执行,不会跨线程传递或逃逸,可以直接给回调加上@unchecked Sendable标记,告诉编译器跳过Sendable检查。
修改后的代码示例:
func performRequest<T: Decodable>( request: T, onSuccess: @escaping @unchecked Sendable (T) -> Void, onFailure: @escaping @unchecked Sendable (Error) -> Void, onOffline: (@escaping @unchecked Sendable () -> Void)? = nil ) { Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { @Sendable timer in if someCondition { onSuccess(someResult) } else { onFailure(someError) } } }
⚠️ 注意:这个标记相当于你向编译器担保“我会负责线程安全”,如果后续代码不小心把回调传到其他线程,可能会引发数据竞争,所以只适合你能完全掌控回调执行上下文的场景。
3. 把回调封装到容器类中(适合复杂回调场景)
如果你的回调逻辑比较复杂,可以把所有回调封装到一个非Sendable的容器类里,用弱引用捕获容器,再通过MainActor调用容器内的回调。这样既避免了直接捕获非Sendable类型,也能清晰管理回调逻辑。
修改后的代码示例:
// 封装回调的容器类 private class CallbackContainer<T: Decodable> { let onSuccess: (T) -> Void let onFailure: (Error) -> Void let onOffline: (() -> Void)? init(onSuccess: @escaping (T) -> Void, onFailure: @escaping (Error) -> Void, onOffline: (() -> Void)?) { self.onSuccess = onSuccess self.onFailure = onFailure self.onOffline = onOffline } } func performRequest<T: Decodable>( request: T, onSuccess: @escaping (T) -> Void, onFailure: @escaping (Error) -> Void, onOffline: (() -> Void)? = nil ) { let container = CallbackContainer(onSuccess: onSuccess, onFailure: onFailure, onOffline: onOffline) Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak container] timer in guard let container = container else { timer.invalidate() return } Task { @MainActor in if someCondition { container.onSuccess(someResult) } else { container.onFailure(someError) } if shouldStopTimer { timer.invalidate() } } } }
这个方案的优势是把回调逻辑和Timer逻辑解耦,同时通过弱引用避免了循环引用的风险,适合回调参数较多、逻辑复杂的场景。
备注:内容来源于stack exchange,提问作者Alisa Martirosyan
相关产品推荐
相关产品推荐

