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된 알파벳 토토에이벤트가 발생한다.
만약 debounce 에 4초를 설정한다면 이벤트는 3초내에 다시 발생하므로 무시되어
debounce된 알파벳 토토에 이벤트가발생되지 않는다.
지정된 시간 내에 발생한 최초및 가장 최신의 이벤트를 발생시킨다.
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 = 알파벳 토토.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 = 알파벳 토토.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 = 알파벳 토토.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 = 알파벳 토토.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 = 알파벳 토토.from(test).filter{ $0.hasPrefix(알파벳 토토;f알파벳 토토;) }
filterTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(fox)
next(fish)
completed
sampler 알파벳 토토 의이벤트에따라본래 알파벳 토토 의 이벤트가 전달된다.
전달할 이벤트가 없을때는 무시된다.
예제
let 알파벳 토토 = Observable<Int.interval(0.1, scheduler: MainScheduler.instance)
알파벳 토토.sample(알파벳 토토<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 = 알파벳 토토.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 = 알파벳 토토.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 = 알파벳 토토.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
다른 알파벳 토토의이벤트가 발생하기 전까지를 스킵한다.
예제
let 알파벳 토토 = Observable<Int.interval(0.1, scheduler: MainScheduler.instance)
알파벳 토토.skipUntil(알파벳 토토<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 = 알파벳 토토.from(test).take(2)
takeTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(rabbit)
next(fox)
completed
일정 시간동안의 이벤트만 발생한다.
예제
let 알파벳 토토 = Observable<Int.interval(0.1, scheduler: MainScheduler.instance)
알파벳 토토.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 = 알파벳 토토.from(test).takeLast(2)
takeTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(dog)
next(cat)
completed
http://rxmarbles.com/#takeUntil
다른 알파벳 토토 이벤트가 발생할때까지만 본래 알파벳 토토 의 이벤트를 발생한다.
예제
let 알파벳 토토 = Observable<Int.interval(0.1, scheduler: MainScheduler.instance)
알파벳 토토.takeUntil(알파벳 토토<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 = 알파벳 토토.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 = 알파벳 토토.from(test).takeWhileWithIndex{ (item,index) - Bool in
return index < 2
}
takeWhileTest.subscribe{ event in
print(event)
}.disposed(by: disposeBag)
결과
next(rabbit)
next(fox)
completed
모든 이벤트를 무시한다.
발생되는 이벤트에는 관심이 없고, 에러나 완료만이 의미가 있을때 사용된다.
이벤트를 필터링 할 수 있는 메서드들을 알아보았다.