Combine框架里,关于时间控制大致有debounce、delay、measureInterval、throttle、timeout
下面我们分别介绍他们的区别和使用方法
值的我们注意的是Combine中的pipline是异步流,所以这些时间控制的Operator还是很强大的。
?
debounce
在某些情况下,我们可能会面临事件产生过于频繁的问题,比如用户输入的搜索关键字。如果我们在用户每次输入一个字符时都进行搜索,可能会导致不必要的网络请求。这时候,我们可以使用debounce
来确保只有在用户停止输入一段时间后才进行搜索。?
let publisher = PassthroughSubject<Int, Never>()
// 使用debounce操作符
let debounceCancellable = publisher
.debounce(for: .seconds(3), scheduler: DispatchQueue.main)
.sink { value in
print("Debounce: \(value)")
}
publisher.send(1)
// 等待一段时间
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
publisher.send(2)
}
publisher.send(3)
// 输出结果:
// Debounce: 2
?时间轴
常见用例
在某些情况下,我们希望在接收到事件后等待一段时间再进行处理。例如,在用户点击一个按钮后,我们可能希望延迟一段时间再执行相应的操作,以提供更好的用户体验。
let publisher = PassthroughSubject<Int, Never>()
// 使用debounce操作符
let debounceCancellable = publisher
.delay(for: .seconds(3), scheduler: DispatchQueue.main)
.sink { value in
print("delay: \(value)")
}
publisher.send(1)
// 等待一段时间
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
publisher.send(2)
}
publisher.send(3)
// 输出结果:
// delay: 1
// delay: 3
// delay: 2
?时间轴
常见用例
在某些情况下,我们可能需要知道两个事件之间经过了多长时间,以便根据时间间隔执行不同的操作。例如,在用户进行某个操作后,我们可能希望在一段时间内等待,然后执行一些额外的逻辑。这时候,measureInterval
就能派上用场。
private var cancellables: Set<AnyCancellable> = []
private var lastClickTime: Double = CFAbsoluteTimeGetCurrent()
func simulateButtonClick() {
Just(())
.measureInterval(using: DispatchQueue.main)
.sink { timeInterval in
print(CFAbsoluteTimeGetCurrent() - lastClickTime)
lastClickTime = CFAbsoluteTimeGetCurrent()
}
.store(in: &cancellables)
}
simulateButtonClick()
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
simulateButtonClick()
}
// 输出结果:
// 0.0002
// 2.1025
measureInterval
它能够记录publisher发送数据的间隔时间
常见用例
在异步操作中,有时我们希望在一定时间内得到结果,如果超时就认为操作失败。例如,网络请求超过一定时间没有响应,我们可能希望取消请求并提示用户。
enum MyError: Error {
case timeout
}
let publisher = PassthroughSubject<Int, Never>()
// 使用debounce操作符
let cancellable = publisher
.setFailureType(to: MyError.self)
.timeout(.seconds(1), scheduler: DispatchQueue.main,customError: { MyError.timeout })
.sink(receiveCompletion: { error in
switch error {
case .finished:
print("finished")
case .failure(let failure):
print("failure: \(failure)")
}
}, receiveValue: { value in
print("send: \(value)")
})
publisher.send(1)
等待一段时间
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
publisher.send(2)
}
// 输出结果:
// send: 1
// failure: timeout
?时间轴
常见用例
?
在某些情况下,我们可能希望限制事件的传递速率,以降低处理的频率。例如,在用户输入搜索关键字时,我们可能不希望每次输入都触发搜索请求,而是希望等待用户停止输入一段时间后再触发搜索。这时 throttle
操作符就派上用场了。
let publisher = PassthroughSubject<Int, Never>()
// 使用throttle操作符
let cancellable = publisher
.throttle(for: .seconds(6), scheduler: DispatchQueue.main, latest: true)
.sink { value in
print("Throttle: \(value)")
}
// 发送元素
publisher.send(1)
publisher.send(2)
publisher.send(3)
// 输出结果:
// Debounce: 3
?Parameters:
常见用例