deferred, timer, interval

โฒ๏ธ deferred, timer, interval โ€” ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ ์‹œํ€€์Šค ๋ง›๋ณด๊ธฐ

โ€œ์ŠคํŠธ๋ฆผ์—๋„ ์‹œ๊ณ„๊ฐ€ ํ•„์š”ํ•˜๋‹ค!โ€ RxSwift๋Š” ์ง€์—ฐยท์ฃผ๊ธฐยท์ง€์†์ ์ธ ์ด๋ฒคํŠธ๋ฅผ ์†์‰ฝ๊ฒŒ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.


1๏ธโƒฃ Observable.deferred โ€” ๊ตฌ๋… ์‹œ์ ๋งˆ๋‹ค ์ƒˆ ์‹œํ€€์Šค

var flip = false
let deferred = Observable<String>.deferred {
    flip.toggle()
    return flip ? .just("๐Ÿ”ด") : .just("๐Ÿ”ต")
}

deferred.subscribe(onNext: print) // ๐Ÿ”ด
deferred.subscribe(onNext: print) // ๐Ÿ”ต
  • Cold: ๊ฐ ๊ตฌ๋… ์‹œ ํด๋กœ์ € ์žฌํ‰๊ฐ€.

  • ์˜์กด์„ฑ์ด ์žˆ๋Š” ์ดˆ๊ธฐํ™”(ํ† ํฐ ๊ฐฑ์‹ , ์œ„์น˜ ๊ถŒํ•œ ์š”์ฒญ) ํŒจํ„ด์— ํ™œ์šฉ.


2๏ธโƒฃ Observable.timer โ€” ์ง€์—ฐ ํ›„ 1ํšŒ ๋˜๋Š” ์ฃผ๊ธฐ ๋ฐฉ์ถœ

// 3์ดˆ ๋’ค 1ํšŒ 0 ๋ฐฉ์ถœ
Observable<Int>.timer(.seconds(3), scheduler: MainScheduler.instance)
    .subscribe(onNext: { print($0) })

// 1์ดˆ ๋’ค ์‹œ์ž‘, ๊ทธํ›„ 5์ดˆ๋งˆ๋‹ค ์ฆ๊ฐ€ ์นด์šดํŠธ ๋ฐฉ์ถœ
Observable<Int>.timer(.seconds(1), period: .seconds(5), scheduler: MainScheduler.instance)
  • period ํŒŒ๋ผ๋ฏธํ„ฐ: ์ƒ๋žต ์‹œ ๋‹จ๋ฐœ์„ฑ, ์ง€์ • ์‹œ interval๊ณผ ์œ ์‚ฌ.

  • ์•ฑ ์•Œ๋ฆผยทSplash ์Šคํ‚ต ๋ฒ„ํŠผ ํƒ€์ด๋จธ ๋“ฑ์— ์‚ฌ์šฉ.


3๏ธโƒฃ Observable.interval โ€” ๊ณ ์ • ์ฃผ๊ธฐ ์ŠคํŠธ๋ฆผ

Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .map { "Tick \($0)" }
    .subscribe(onNext: print)
  • 0,1,2,3โ€ฆ ์นด์šดํŠธ ์—…๋ฐ์ดํŠธ.

  • ์ฃผ๊ฐ€ ์ฐจํŠธ, ์šด๋™ ํƒ€์ด๋จธ, ์‹ค์‹œ๊ฐ„ ์„ผ์„œ ๋“ฑ ๋ฐ˜๋ณต ์ž‘์—….


4๏ธโƒฃ Scheduler & Threading

Scheduler ์„ ํƒ
ํšจ๊ณผ

MainScheduler

UI ํƒ€์ด๋จธ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์ง„ํ–‰

ConcurrentDispatchQueueScheduler

๋ฐฑ๊ทธ๋ผ์šด๋“œ ํด๋ง ์ž‘์—…

TestScheduler

๊ฐ€์ƒ ์‹œ๊ฐ„ ํ…Œ์ŠคํŠธ (advanceTo, start)

iOS ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์ œํ•œ์—์„œ ๊ธด interval์€ WKBackgroundTask ๋Œ€์•ˆ ๊ณ ๋ ค.


5๏ธโƒฃ ์กฐํ•ฉ ์˜ˆ์‹œ โ€” 10์ดˆ ์นด์šดํŠธ๋‹ค์šด

func countdown(from n: Int) -> Observable<Int> {
    Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
        .map { n - $0 }
        .take(n + 1) // 0๊นŒ์ง€ ํฌํ•จ
}

countdown(from: 10)
    .subscribe(onNext: { print($0) },
               onCompleted: { print("Go!") })

6๏ธโƒฃ Memory & Cancellation

  • DisposeBag ๋˜๋Š” .takeUntil(trigger)๋กœ ์˜ˆ์•ฝ ์ž‘์—… ์ทจ์†Œ.

  • timer/interval์€ ๋‚ด๋ถ€ GCD Timer โ€” retain ์ฃผ์˜ (disposed(by:)).

let task = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
    .subscribe(...)

DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
    task.dispose() // ํƒ€์ด๋จธ ์ทจ์†Œ
}

7๏ธโƒฃ Mini Quiz

  1. timer์™€ interval์˜ ์ฃผ๊ธฐ ๋ฐฉ์ถœ ์ฐจ์ด?

  2. deferred๋ฅผ ํ™œ์šฉํ•ด ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅธ API ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•˜๋ ค๋ฉด? (๊ฐœ๋… ์„ค๋ช…)

  3. interval ์ŠคํŠธ๋ฆผ์„ ์ผ์‹œ ์ค‘์ง€ํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์–ด๋–ค ์˜คํผ๋ ˆ์ดํ„ฐ ์กฐํ•ฉ์ด ์œ ์šฉํ• ๊นŒ?

Answers
  1. timer๋Š” ์ง€์—ฐ ํ›„ 1ํšŒ(period ์—†์„ ๋•Œ) ๋˜๋Š” ์ง€์—ฐ ํ›„ ์ฃผ๊ธฐ(period ์‚ฌ์šฉ) / interval์€ ์ฆ‰์‹œ or 0 ์ง€์—ฐ ํ›„ ์ฃผ๊ธฐ โ€” ์‹คํ–‰ ๋ฐฉ์‹ ์œ ์‚ฌํ•˜๋‚˜ timer๋Š” ์ฒซ ๋”œ๋ ˆ์ด ์ง€์ • ๊ฐ€๋Šฅ.

  2. Observable.deferred { isLoggedIn ? api.userInfo() : Observable.error(AuthError.noLogin) } ์ฒ˜๋Ÿผ ๊ตฌ๋… ์‹œ์ ์— ์ƒํƒœ๋ฅผ ์ฒดํฌํ•ด ์•Œ๋งž์€ ์‹œํ€€์Šค๋ฅผ ๋ฐ˜ํ™˜.

  3. interval โ†’ .pausable(trigger)(RxExt) ๋˜๋Š” withLatestFrom(pause) + flatMapLatest๋ฅผ ์‚ฌ์šฉํ•ด Trigger๊ฐ€ false์ผ ๋• ํŒ์ • ์Šคํ‚ต.


๐ŸŽ‰ CreatingSequences ์ฑ•ํ„ฐ ์™„๋ฃŒ! ์ด์ œ Operators(Filtering) ํŒŒํŠธ๋กœ ์ด๋™ํ•ด ์ŠคํŠธ๋ฆผ ๊ฐ€๊ณต์„ ์‹œ์ž‘ํ•ด ๋ด…์‹œ๋‹ค. ๐Ÿš€

Last updated