Swift Combine实现不丢弃值的Debounce功能需求求助
实现带元素合并的Debounce效果(Swift Combine)
原Combine的debounce操作符会在指定时间间隔内仅保留最后一个元素、丢弃中间元素。如果需要将这段间隔内的所有元素合并为数组输出,可参考以下实现方案。
原代码示例
let bounces:[(Int,TimeInterval)] = [ (0, 0), (1, 0.25), // 距上一个元素间隔0.25秒 (2, 1), // 距上一个元素间隔0.75秒 (3, 1.25), // 距上一个元素间隔0.25秒 (4, 1.5), // 距上一个元素间隔0.25秒 (5, 2) // 距上一个元素间隔0.5秒 ] let subject = PassthroughSubject<Int, Never>() cancellable = subject .debounce(for: .seconds(0.5), scheduler: RunLoop.main) .sink { index in print("Received index \(index)") } for bounce in bounces { DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) { subject.send(bounce.0) } } // 原输出: // Received index 1 // Received index 4 // Received index 5
预期输出
// 期望输出: // Received index [0, 1] // Received index [2, 3, 4] // Received index [5]
解决方案代码
利用Combine的window操作符结合collect,实现元素合并的Debounce效果:
let bounces:[(Int,TimeInterval)] = [ (0, 0), (1, 0.25), // 距上一个元素间隔0.25秒 (2, 1), // 距上一个元素间隔0.75秒 (3, 1.25), // 距上一个元素间隔0.25秒 (4, 1.5), // 距上一个元素间隔0.25秒 (5, 2) // 距上一个元素间隔0.5秒 ] let subject = PassthroughSubject<Int, Never>() cancellable = subject // 开启窗口:元素发送后,若连续0.5秒无新元素则闭合窗口 .window(dueTime: .seconds(0.5), scheduler: RunLoop.main) // 将窗口内的所有元素收集为数组 .flatMap { windowSequence in windowSequence.collect() } // 过滤空数组(避免无元素时输出无效内容) .filter { !$0.isEmpty } .sink { indices in print("Received index \(indices)") } for bounce in bounces { DispatchQueue.main.asyncAfter(deadline: .now() + bounce.1) { subject.send(bounce.0) } } // 实际输出: // Received index [0, 1] // Received index [2, 3, 4] // Received index [5]
逻辑说明
window(dueTime: .seconds(0.5), scheduler: RunLoop.main):每次收到元素时开启一个窗口,若窗口结束前有新元素到来,会以新元素的发送时间为起点重新计算0.5秒窗口时长,直到连续0.5秒无新元素输入,窗口才会闭合。flatMap + collect():将每个窗口对应的元素序列转换为数组,实现间隔内元素的合并。filter:过滤空数组,避免因长时间无元素输入而输出无效内容。
内容的提问来源于stack exchange,提问作者Tengfei
相关产品推荐
相关产品推荐

