我想去反弹一个值流,并向其添加刷新信号。当刷新信号出现时,去抖应立即发出其上次接收的值并清除其缓冲区。如果去抖动缓冲区中没有值,则刷新信号不执行任何操作。基本上,冲洗信号暂时将去抖动时间设置为 0:
values: -- 1 -- 2 -- 3 ---------- 4 -- 5 -- 6 --------------------
flush: --------------------------------- * -------------- * -----
output: ------------------- 3 ----------- 5 ------- 6 ------------
我尝试了以下方法,用delay
和switchToLatest
模仿debounce
,但无法弄清楚如何flushedValues
,它应该发出最后一个值(如果有的话),该值在刷新信号前 2 秒内出现。
// valuesSubject: Publisher<Int, Never> is the value stream
// flushSubject: Publisher<Void, Never> is the flush stream
let valuesWithDelay = valuesSubject.map { $0.delay(for: 2, scheduler: ...) }
let flushedValues = // somehow combine valuesSubject and flushSubject
let output = Publishers.Merge(valuesWithDelay, flushedValues).switchToLatest()
我想出的解决方案如下。
对于发出的每个值,它会创建一个Future
,该将在经过足够的时间或发送刷新时解析。
然后将这些期货传递给switchToLatest
。 如果您快速发出值(低于去抖动阈值),那么最新的未来将替换任何旧的未来。只有"最新"才有机会发出值。
import Cocoa
import Combine
import PlaygroundSupport
import SwiftUI
let flush = PassthroughSubject<Void, Never>()
let values = Timer.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
.scan(0) { prev, _ in prev + 1}
.filter { $0 % 10 < 3 }
let output = values
.map { value in
return Future<Int, Never> { fulfill in
var flushValue : AnyCancellable?
var waitForValue : AnyCancellable?
flushValue = Just(value)
.combineLatest(flush) { value, _ in return value }
.sink {
waitForValue?.cancel()
fulfill(.success($0))
}
waitForValue = Just(value)
.delay(for: 0.3, scheduler: RunLoop.main)
.sink (
receiveValue: {
flushValue?.cancel()
fulfill(.success($0))
})
}
}
.switchToLatest()
.sink { debugPrint($0) }
struct FlushButtonView : View {
var body : some View {
Button("Flush") { flush.send(()) }
}
}
PlaygroundSupport.PlaygroundPage.current.liveView = NSHostingController(rootView: FlushButtonView())