Debounce, Distinct, Filter, Take, Skip등
* 이 포스트는 RxSwift 4.3.1, swift 4.2 버전을 기준으로 작성되었습니다.
이벤트들을 특정 조건이 맞을때 발생하도록 이벤트를 필터링 하는 메서드들에 대해 알아보자
http://rxmarbles.com/#debounce
지정한 시간간격 내에 마지막 하나의 이벤트만 전달한다.
아래 그림처럼 이벤트 간격이 설정(debounce)한 시간대 값보다 짧은 타이밍으로 연속된다면 이벤트가 일어나지 않는다.
예제
let timer = Observable<Int>.interval(3, scheduler: MainScheduler.instance)
timer.debounce(1, scheduler: MainScheduler.instance).debug()
.subscribe().disposed(by: disposeBag)
결과
2018-10-06 22:24:05.526: (timer) -> Event next(0)
2018-10-06 22:24:06.527: (debounceTest()) -> Event next(0)
2018-10-06 22:24:08.526: (timer) -> Event next(1)
2018-10-06 22:24:09.528: (debounceTest()) -> Event next(1)
2018-10-06 22:24:11.525: (timer) -> Event next(2)
2018-10-06 22:24:12.526: (debounceTest()) -> Event next(2)
시간값을 보면 3초마다 발생한 timer 가 발생하고 debounce 에서 설정한 1초 내에 다른 이벤트가 발생하지 않으므로 1초뒤 debounce된 Observable에 이벤트가 발생한다.
만약 debounce 에 4초를 설정한다면 이벤트는 3초내에 다시 발생하므로 무시되어
debounce된 Observable에 이벤트가 발생되지 않는다.
지정된 시간 내에 발생한 최초및 가장 최신의 이벤트를 발생시킨다.
debounce 와는 동작이 다르다.
예제
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
timer.throttle(3, scheduler: MainScheduler.instance).debug()
.subscribe().disposed(by: disposeBag)
결과
2018-10-06 22:29:34.234: (timer) -> Event next(0)
2018-10-06 22:29:34.235: (throttleTest()) -> Event next(0)
2018-10-06 22:29:35.234: (timer) -> Event next(1)
2018-10-06 22:29:36.234: (timer) -> Event next(2)
2018-10-06 22:29:37.234: (timer) -> Event next(3)
2018-10-06 22:29:37.234: (throttleTest()) -> Event next(3)
2018-10-06 22:29:38.234: (timer) -> Event next(4)
2018-10-06 22:29:39.234: (timer) -> Event next(5)
subscribe 된 시점에 이벤트가 발생되고, 이후 3초 간 발생한 이벤트중 가장 최근의 것을 발생시킨다.
유저 탭 이벤트등의 연속된 호출을 간단하게 필터링 할수 있다.
http://rxmarbles.com/#distinct
이전 이벤트와 비교해서 값이 다를 경우에만 이벤트를 방출한다.
같은 원소인지 비교해서 다른 원소일때에만 이벤트가 방출된다.
예제
let test = ["a","a","b","c","c","c"]
let distinctTest = Observable.from(test).distinctUntilChanged()
distinctTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(a)
next(b)
next(c)
completed
예제
struct Fish {
var name = ""
var skinColor = ""
}
let nimo = Fish(name: "nimo", skinColor: "red")
let dori = Fish(name: "dori", skinColor: "blue")
let dori2 = Fish(name: "dori2", skinColor: "blue")
let test = [nimo,nimo,dori,dori,dori2,nimo]
let distinctTest = Observable.from(test).distinctUntilChanged { $0.skinColor }
distinctTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
Equatable type 이 아닌 객체를 key 를 지정해서 비교할 수 있는 코드이다.
피부색을 비교하도록 했으므로, dori,dori2 는 같은 이벤트로 판단할 것이다.
결과
next((Fish #1)(name: "nimo", skinColor: "red"))
next((Fish #1)(name: "dori", skinColor: "blue"))
next((Fish #1)(name: "nimo", skinColor: "red"))
completed
예제
let test = [nimo,nimo,dori,dori,dori2,nimo]
let distinctTest = Observable.from(test).distinctUntilChanged { (lhs, rhs) -> Bool in
return lhs.name == rhs.name
}
distinctTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
위의 예제에서 skinColor 가 아닌, name 값으로 비교하도록 변경한 것이다.
결과
next((Fish #1)(name: "nimo", skinColor: "red"))
next((Fish #1)(name: "dori", skinColor: "blue"))
next((Fish #1)(name: "dori2", skinColor: "blue"))
next((Fish #1)(name: "nimo", skinColor: "red"))
completed
http://rxmarbles.com/#elementAt
지정한 index 의 이벤트만 발생하도록 하는 메서드이다.
예제
let test = ["a","a","b","c","c","c"]
let elementAtTest = Observable.from(test).elementAt(2)
elementAtTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(b)
completed
첫번째 이벤트만 발생시킨다.
RxSwift 에서는 single 메서드로 쓰인다.
예제 생략
조건식에 부합하는 이벤트만 발생시킨다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let filterTest = Observable.from(test).filter{ $0.hasPrefix("f") }
filterTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(fox)
next(fish)
completed
sampler observable 의 이벤트에 따라 본래 observable 의 이벤트가 전달된다.
전달할 이벤트가 없을때는 무시된다.
예제
let observable = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
observable.sample(Observable<Int>.interval(0.5, scheduler: MainScheduler.instance))
.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(4)
next(9)
next(14)
next(19)
next(24)
...
0.1 초 이벤트가 발생하지만, 0.5초 이벤트 Observable sampler를 통해, 위와 같은 결과를 보인다.
n개의 이벤트를 스킵한다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let skipTest = Observable.from(test).skip(3)
skipTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(dog)
next(cat)
completed
특정 이벤트 발생전까지 이벤트를 skip 한다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let skipTest = Observable.from(test).skipWhile{ $0 != "fish" }
skipTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(fish)
next(dog)
next(cat)
completed
deprecate 되었다. enumerate().skipWhile().map() 을 사용하면 된다.
skipWhile 과 기본적으로 동일하나 index 를 사용할수 있다.
예제
let test = ["rabbit","fox","fish","fox","cat"]
let skipTest = Observable.from(test).skipWhileWithIndex{ (item, index) -> Bool in
return index < 3 || item != "fox"
}
skipTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(fox)
next(cat)
completed
http://rxmarbles.com/#skipUntil
다른 Observable의 이벤트가 발생하기 전까지를 스킵한다.
예제
let observable = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
observable.skipUntil(Observable<Int>.interval(0.5, scheduler: MainScheduler.instance))
.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(5)
next(6)
next(7)
next(8)
...
n개의 이벤트만 발생한다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let takeTest = Observable.from(test).take(2)
takeTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(rabbit)
next(fox)
completed
일정 시간동안의 이벤트만 발생한다.
예제
let observable = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
observable.take(0.3, scheduler: MainScheduler.instance)
.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(0)
next(1)
http://rxmarbles.com/#takeLast
완료가 되면 count 만큼 이전의 이벤트를 발생한다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let takeTest = Observable.from(test).takeLast(2)
takeTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(dog)
next(cat)
completed
http://rxmarbles.com/#takeUntil
다른 Observable 이벤트가 발생할때까지만 본래 Observable 의 이벤트를 발생한다.
예제
let observable = Observable<Int>.interval(0.1, scheduler: MainScheduler.instance)
observable.takeUntil(Observable<Int>.interval(0.5, scheduler: MainScheduler.instance))
.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(0)
next(1)
next(2)
next(3)
completed
조건식에 부합될때까지만 이벤트를 발생한다.
예제
let test = ["rabbit","fox","fish","dog","cat"]
let takeWhileTest = Observable.from(test).takeWhile{ $0 != "fish" }
takeWhileTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(rabbit)
next(fox)
completed
deprecate 되었다. enumerate().takeWhile().map() 을 사용하면 된다.
기본적으로 takeWhile 이며 인덱스를 사용할수 있다.
예제
let test = ["rabbit","fox","fish","fox","cat"]
let takeWhileTest = Observable.from(test).takeWhileWithIndex{ (item,index) -> Bool in
return index < 2
}
takeWhileTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(rabbit)
next(fox)
completed
모든 이벤트를 무시한다.
발생되는 이벤트에는 관심이 없고, 에러나 완료만이 의미가 있을때 사용된다.
이벤트를 필터링 할 수 있는 메서드들을 알아보았다.