Search

RxSwift - Time-based Operator

ย Time-based Operator

Time-shifting Operator

์ด๋ฒคํŠธ ๋ฐฉ์ถœ์„ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.

delaySubscription

๊ตฌ๋…์ด ์‹œ์ž‘๋˜๋Š” ์‹œ์ ์„ ์ง€์—ฐ
delaySubscription์€ ๊ตฌ๋…์ด ์‹œ์ž‘๋˜๋Š” ์‹œ์ ์ด ์ง€์—ฐ๋˜๋Š”๊ฑฐ์ง€, next ์ด๋ฒคํŠธ์˜ ์ „๋‹ฌ์€ ์ง€์—ฐ๋˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance) .take(6) .delaySubscription(.seconds(3), scheduler: MainScheduler.instance) .subscribe { print($0) } .disposed(by: disposeBag) /* 3์ดˆ๊ฐ€ ์ง€๋‚œ ํ›„์—... next(0) next(1) next(2) next(3) next(4) next(5) completed */
Swift
๋ณต์‚ฌ

delay

next ์ด๋ฒคํŠธ๊ฐ€ ์ „๋‹ฌ๋˜๋Š” ์‹œ์ ์„ ์ง€์—ฐ
delaySubscription๊ณผ๋Š” ๋ฐ˜๋Œ€๋กœ ๊ตฌ๋… ์‹œ์ ์„ ์ง€์—ฐ์‹œํ‚ค์ง€ ์•Š๊ณ , next ์ด๋ฒคํŠธ์˜ ์ „๋‹ฌ์„ ์ง€์—ฐ์‹œํ‚ต๋‹ˆ๋‹ค.
Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance) .take(6) .debug() .delay(.seconds(3), scheduler: MainScheduler.instance) .subscribe { print($0) } .disposed(by: disposeBag) // subscribed๋Š” ์ง€์—ฐ๋˜์ง€ ์•Š์ง€๋งŒ, next ์ด๋ฒคํŠธ๊ฐ€ ๋‚˜์˜ค๋Š”๊ฑด 3์ดˆ ๋’ค๋ถ€ํ„ฐ /* (bind()) -> subscribed (bind()) -> Event next(0) (bind()) -> Event next(1) (bind()) -> Event next(2) (bind()) -> Event next(3) next(0) (bind()) -> Event next(4) next(1) (bind()) -> Event next(5) (bind()) -> Event completed (bind()) -> isDisposed next(2) next(3) next(4) next(5) completed */
Swift
๋ณต์‚ฌ

Timer Operator

์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋˜๋Š” ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์„ ์„ค์ • ๊ฐ€๋Šฅํ•œ ์—ฐ์‚ฐ์ž์ž…๋‹ˆ๋‹ค.

interval

์ง€์ •๋œ ์ฃผ๊ธฐ๋งˆ๋‹ค ์ •์ˆ˜ ํƒ€์ž…์˜ ๊ฐ’์„ ๋ฐฉ์ถœ
์ง€์ •๋œ ์ฃผ๊ธฐ๋งˆ๋‹ค ์ •์ˆ˜ ํƒ€์ž…์˜ ๊ฐ’์„ ์ง€์†์ ์œผ๋กœ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ํ•ด๋‹น Observable์„ ์ค‘์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” .take ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐœํ–‰๋˜๋Š” ์ด๋ฒคํŠธ์˜ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ฑฐ๋‚˜, dispose๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
Observable<Int> .interval(.nanoseconds(1), scheduler: MainScheduler.instance) .take(until: { $0 == 20 }, behavior: .inclusive) .subscribe { print($0, terminator: " ") } .disposed(by: disposeBag) /* next(0) next(1) next(2) next(3) next(4) next(5) next(6) next(7) next(8) next(9) next(10) next(11) next(12) next(13) next(14) next(15) next(16) next(17) next(18) next(19) next(20) completed */
Swift
๋ณต์‚ฌ

timer

์ง€์—ฐ ์‹œ๊ฐ„๊ณผ ๋ฐ˜๋ณต ์ฃผ๊ธฐ๋ฅผ ์ง€์ •ํ•ด์„œ ์ •์ˆ˜ ํƒ€์ž…์˜ ๊ฐ’ ๋ฐฉ์ถœ
timer๋„ interval๊ณผ ๋™์ผํ•˜๊ฒŒ Observable์„ ์ค‘์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” .take๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฐœํ–‰๋˜๋Š” ์ด๋ฒคํŠธ ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ฑฐ๋‚˜, dispose๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. interval๊ณผ๋Š” ๋‹ค๋ฅด๊ฒŒ dueTime๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์ด๋ฒคํŠธ ๋ฐœํ–‰์ด ์ง€์—ฐ๋˜๋Š” ์‹œ๊ฐ„์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
Observable<Int>.timer(.seconds(3), period: .seconds(1), scheduler: MainScheduler.instance) .take(until: { $0 == 10 }, behavior: .inclusive) .subscribe{ print($0, terminator: " ") } .disposed(by: disposeBag) /* next(0) next(1) next(2) next(3) next(4) next(5) next(6) next(7) next(8) next(9) next(10) completed */
Swift
๋ณต์‚ฌ

timeout

์ง€์ •๋œ ์‹œ๊ฐ„ ์ด๋‚ด์— ์š”์†Œ๋ฅผ ๋ฐฉ์ถœํ•˜์ง€ ์•Š์œผ๋ฉด ์—๋Ÿฌ ์ด๋ฒคํŠธ ์ „๋‹ฌ
โ€ข
์—๋Ÿฌ ๋ฐฉ์ถœ
let subject = PublishSubject<Int>() subject.timeout(.seconds(3), scheduler: MainScheduler.instance) .subscribe{ print($0) } .disposed(by: disposeBag) // ์•„๋ฌด๋Ÿฐ ์ด๋ฒคํŠธ๋„ ๋ฐฉ์ถœ๋˜์ง€ ์•Š์•„์„œ 3์ดˆ ๋’ค์— ์—๋Ÿฌ ์ด๋ฒคํŠธ๊ฐ€ ์ „๋‹ฌ /* error(Sequence timeout.) */
Swift
๋ณต์‚ฌ
โ€ข
์ •์ƒ ์ž‘๋™
let subject = PublishSubject<Int>() subject.timeout(.seconds(3), other: Observable.just(1), scheduler: MainScheduler.instance) .subscribe{ print($0) } .disposed(by: disposeBag) Observable<Int>.timer(.seconds(2), period: .seconds(5), scheduler: MainScheduler.instance) .subscribe(onNext: { subject.onNext($0) }) .disposed(by: disposeBag) // ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋๊ธฐ ๋•Œ๋ฌธ์— ์—๋Ÿฌ ์ด๋ฒคํŠธ๊ฐ€ ์ „๋‹ฌ๋˜์ง€ ์•Š์Œ /* next(0) next(1) completed */
Swift
๋ณต์‚ฌ

debounce

ํƒ€์ด๋จธ๋ฅผ ์ง€์ •ํ•ด๋‘๊ณ  ํƒ€์ด๋จธ๊ฐ€ ๋๋‚œ ์‹œ์ ์— ๊ฐ€์žฅ ์ตœ๊ทผ์˜ ๊ฐ’์„ ๋ฐฉ์ถœ
์—ฐ์†์ ์ธ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ํŠน์ • ์‹œ๊ฐ„ ๋ฒ”์œ„๋™์•ˆ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰์— ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ๋งŒ ๋ฐฉ์ถœ๋˜๊ณ  ๋‚˜๋จธ์ง€ ์—ฐ์†์ ์ธ ์ด๋ฒคํŠธ๋Š” blockํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.
debounce๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋  ๋•Œ๋งˆ๋‹ค ํƒ€์ด๋จธ๊ฐ€ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
textField.rx.text.orEmpty .debounce(.seconds(1), scheduler: MainScheduler.asyncInstance) .subscribe(onNext: { text in print(text) }) .disposed(by: disposeBag) // ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ์งํ›„ 1์ดˆ๋™์•ˆ ์–ด๋– ํ•œ ๋‹ค๋ฅธ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ทธ๋Œ€๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋˜๊ณ , // ์—ฐ์†์ ์œผ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด block ํ•ด์ฃผ๋Š” ์—ญํ• 
Swift
๋ณต์‚ฌ

throttle

ํƒ€์ด๋จธ๋ฅผ ์ง€์ •ํ•ด๋‘๊ณ  ์ด๋ฒคํŠธ๊ฐ€ ์ฒ˜์Œ ๋ฐฉ์ถœ๋˜๋ฉด ์ง€์ •๋œ ์‹œ๊ฐ„๋™์•ˆ ์–ด๋–ค ์ด๋ฒคํŠธ๋„ ๋ฐฉ์ถœํ•˜์ง€ ์•Š์Œ
throttle๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ตœ์†Œ ๊ฐ„๊ฒฉ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š” Operator์ž…๋‹ˆ๋‹ค. ์–ด๋–ค ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋˜๋Š” ์‹œ์ ์—์„œ ์ง€์ •ํ•œ ์‹œ๊ฐ„๋™์•ˆ ์ด๋ฒคํŠธ๋“ค์„ blockํ•จ์œผ๋กœ์จ, ์ด๋ฒคํŠธ๊ฐ€ ๋ฐฉ์ถœ๋˜๋Š” ๊ฐ„๊ฒฉ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
โ€ข
latest = true
throttle์—๋Š” latest๋ผ๋Š” ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์žˆ๋Š”๋ฐ ํ•ด๋‹น ์˜์—ญ์„ true๋กœ ์„ค์ •ํ•˜๊ฒŒ ๋˜๋ฉด, ์ง€์ • ์‹œ๊ฐ„ ๋’ค์— ๊ฐ€์žฅ ์ตœ๊ทผ ๊ฐ’์„ ํ•œ ๋ฒˆ ๋” ๋ฐฉ์ถœํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance) .take(10) .throttle(.seconds(2), latest: true, scheduler: MainScheduler.instance) .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) // emit(0) - 1 - emit(2) - 3 - emit(4) - 5 - emit(6) - 7 - emit(8) - 9 - emit(9) - completed /* 0 2 4 6 8 9 */
Swift
๋ณต์‚ฌ
โ€ข
latest = false
latest๊ฐ€ false๋ฉด ์ฒ˜์Œ ๋ฐฉ์ถœ๋œ ์ด๋ฒคํŠธ๋งŒ ๋ฐฉ์ถœ๋˜๊ณ  ํƒ€์ด๋จธ ์‹œ๊ฐ„๋™์•ˆ ์–ด๋–ค ์ด๋ฒคํŠธ๋„ ๋ฐฉ์ถœ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance) .take(10) .throttle(.seconds(2), latest: false, scheduler: MainScheduler.instance) .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) // emit(0) - 1 - emit(2) - 3 - emit(4) - 5 - emit(6) - 7 - emit(8) - 9 - completed /* 0 2 4 6 8 */
Swift
๋ณต์‚ฌ
debounce์™€ throttle๋Š” ๋น„์Šทํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ์ฐจ์ด๊ฐ€ ์žˆ๋‚˜์š”?
โ€ข
debounce
debounce๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ์—์„œ, ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ์ด๋ฒคํŠธ๋งŒ์„ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.
์ฆ‰, ์‹œ๊ฐ„ ๊ฐ’์ด 1์ดˆ์ผ ๋•Œ ์ค‘๋ณต์œผ๋กœ 99์ดˆ๋™์•ˆ 100๋ฒˆ ๋ˆ„๋ฅด๋ฉด 1๋ฒˆ ๋ฐ˜์˜๋˜๋Š” ๊ฒƒ์ด debounce ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, debounce๋Š” ์ž๋™์™„์„ฑ์ด๋‚˜ ์—ฐ๊ด€๊ฒ€์ƒ‰์–ด ๋…ธ์ถœ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
ํ…์ŠคํŠธ ํ•„๋“œ์— ํ…์ŠคํŠธ๊ฐ€ ์—ฌ๋Ÿฌ๋ฒˆ ๋“ค์–ด์˜ค๋Š” ๋™์•ˆ์€ ํ•ด๋‹น ํ…์ŠคํŠธ๋ฅผ ๋ฐฉ์ถœํ•˜์ง€ ์•Š๋‹ค๊ฐ€ ์ž ๊น ๋ฉˆ์ถ”๋Š” ๋™์•ˆ ํ•ด๋‹น ํ…์ŠคํŠธ๋ฅผ ์ž๋™์™„์„ฑํ•˜๊ฑฐ๋‚˜ ์—ฐ๊ด€๊ฒ€์ƒ‰์–ด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฒƒ์ด์ฃ . ์•„๋‹ˆ๋ผ๋ฉด, ์„œ๋ฒ„์— ํ•ด๋‹น ํ…์ŠคํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•˜๋Š” ์ˆœ๊ฐ„์ˆœ๊ฐ„์—๋„ ์š”์ฒญ์„ ํ•˜๊ฒŒ ๋  ๊ฒ๋‹ˆ๋‹ค.
โ€ข
throttle
throttle๋Š” ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ผ์ • ์‹œ๊ฐ„๋™์•ˆ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.
์ฆ‰, ์‹œ๊ฐ„ ๊ฐ’์ด 1์ดˆ์ผ ๋•Œ 0.9์ดˆ๋™์•ˆ 100๋ฒˆ ๋ˆ„๋ฅด๋ฉด 2๋ฒˆ ๋ฐ˜์˜(latest = true)๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์—, throttle๋Š” ๋ฒ„ํŠผ ํƒญ์ด๋‚˜ ์Šคํฌ๋กค์„ ๋‚ด๋ฆฌ๋ฉด์„œ ๋ช‡ ์ฒœ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•  ๋•Œ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ, ํƒญ์ด ์ค‘๋ณต์ ์œผ๋กœ ๋ˆŒ๋Ÿฌ์ง„๋‹ค๋ฉด ์ž˜๋ชป๋œ ์š”์ฒญ์ด ์ „๋‹ฌ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ํƒญ์ด ๋ฐœ์ƒํ•˜๊ณ ๋‚˜์„œ ๋ช‡ ์ดˆ๋™์•ˆ ํƒญ์„ ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด ์ž˜๋ชป๋œ ๊ฐ’์ด ์ „๋‹ฌ๋  ์œ„ํ—˜์ด ์ค„์–ด๋“ค๊ฒŒ ๋  ๊ฒƒ ์ž…๋‹ˆ๋‹ค.