Swift中1秒未收事件时将@Published变量置为nil的最简实现方案
实现方案
你可以用苹果原生的Combine响应式框架实现,代码非常简洁,核心利用了流合并和防抖延迟的能力,完整代码如下:
import Combine enum MyEnum { // 你的枚举定义 } class MyController: NSObject, ObservableObject { @Published var myRapidlyChangingVar: MyEnum? = nil // 用于接收方法调用的事件流 private let valueSubject = PassthroughSubject<MyEnum, Never>() private var cancellables = Set<AnyCancellable>() override init() { super.init() // 绑定流逻辑 valueSubject .map { $0 as MyEnum? } // 合并两条流:1. 收到值立即发送当前值 2. 防抖1秒后发送nil .merge( with: valueSubject .debounce(for: .seconds(1), scheduler: DispatchQueue.main) .map { _ in nil } ) .assign(to: \.myRapidlyChangingVar, on: self) .store(in: &cancellables) } func calledAtHighFrequencyByExternalEvents(value: MyEnum) { // 仅需要发送事件到流即可 valueSubject.send(value) } }
核心逻辑说明
- 每次方法调用时会向事件流发送最新的枚举值,流会立即把值赋值给
myRapidlyChangingVar - 同时
debounce操作符会启动1秒计时,如果1秒内没有新的事件传入,就会发送nil重置变量 - 如果1秒内有新的方法调用,会自动重置计时,完全符合连续1秒未调用才重置的需求
- 你可以搜索
Combine debounce、iOS idle timeout、Combine 延迟防抖作为相关关键词查询更多资料
非响应式的极简实现(GCD方案)
如果不想引入Combine,用GCD的DispatchWorkItem也可以实现,代码量更少:
class MyController: NSObject, ObservableObject { @Published var myRapidlyChangingVar: MyEnum? = nil private var pendingResetTask: DispatchWorkItem? func calledAtHighFrequencyByExternalEvents(value: MyEnum) { myRapidlyChangingVar = value // 取消上一次未执行的重置任务 pendingResetTask?.cancel() // 创建新的重置任务 let resetTask = DispatchWorkItem { [weak self] in self?.myRapidlyChangingVar = nil } pendingResetTask = resetTask DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: resetTask) } }
内容的提问来源于stack exchange,提问作者Andrew Ebling
相关产品推荐
相关产品推荐

