Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Works like `debounce` except if an empty string is pushed in, it will emit immediately.
class Tests: XCTestCase {
var scheduler: TestScheduler!
var result: TestableObserver<String>!
var disposeBag: DisposeBag!
override func setUp() {
super.setUp()
scheduler = TestScheduler(initialClock: 0, resolution: 0.1)
result = scheduler.createObserver(String.self)
disposeBag = DisposeBag()
}
func test1() {
let source = scheduler.createColdObservable([.next(0, ""), .next(10, "H"), .next(20, "He"), .next(40, "Hel")])
source
.clearingDebounce(.seconds(1), scheduler: scheduler)
.subscribe(result)
.disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(result.events, [.next(0, ""), .next(30, "He"), .next(50, "Hel")])
}
func test2() {
let source = scheduler.createColdObservable([.next(0, ""), .next(10, "H"), .next(20, "He"), .next(40, "")])
source
.clearingDebounce(.seconds(1), scheduler: scheduler)
.subscribe(result)
.disposed(by: disposeBag)
scheduler.start()
XCTAssertEqual(result.events, [.next(0, ""), .next(30, "He"), .next(40, "")])
}
}
//
// ClearningDebounce.swift
//
// Created by Daniel Tartaglia on 21 Aug 2019.
// Copyright © 2019 Daniel Tartaglia. MIT License.
//
import RxSwift
extension ObservableType where Element == String {
func clearingDebounce(_ dueTime: RxTimeInterval, scheduler: SchedulerType) -> Observable<String> {
var _id = 0 as UInt64
var _value: Element? = nil
let cancellable = SerialDisposable()
let lock = NSRecursiveLock()
return Observable.create { observer in
func propagate(_ currentId: UInt64) -> Disposable {
lock.lock(); defer { lock.unlock() }
let originalValue = _value
if let value = originalValue, _id == currentId {
_value = nil
observer.onNext(value)
}
return Disposables.create()
}
let disposable = self.subscribe { event in
switch event {
case .next(let element):
if element.isEmpty {
cancellable.disposable.dispose()
_value = element
observer.onNext(element)
}
else {
_id += 1
_value = element
let disp = SingleAssignmentDisposable()
cancellable.disposable = disp
disp.setDisposable(scheduler.scheduleRelative(_id, dueTime: dueTime, action: propagate))
}
case .error(let error):
observer.onError(error)
case .completed:
observer.onCompleted()
}
}
return disposable
}
}
}
extension TimeInterval {
init?(_ dispatchTimeInterval: RxTimeInterval) {
switch dispatchTimeInterval {
case .seconds(let value):
self = Double(value)
case .milliseconds(let value):
self = Double(value) / 1_000
case .microseconds(let value):
self = Double(value) / 1_000_000
case .nanoseconds(let value):
self = Double(value) / 1_000_000_000
case .never:
return nil
@unknown default:
fatalError()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment