Observers

๐Ÿ‘€ Observers โ€” ์ŠคํŠธ๋ฆผ์„ โ€˜๊ด€์ฐฐโ€™ํ•˜๋Š” ์กด์žฌ

Observer = ์ŠคํŠธ๋ฆผ ์†Œ๋น„์ž. Observable์ด ๋ฐ์ดํ„ฐ๋ฅผ "๋ฐœํ–‰"(push)ํ•˜๋ฉด, Observer๋Š” ์ด๋ฅผ "๊ตฌ๋…"(pull X)ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ด ์žฅ์—์„œ๋Š” RxSwift์—์„œ Observer๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋ฉฐ, ์‹ค์ œ ํ”„๋กœ์ ํŠธ์—์„œ ์–ด๋–ป๊ฒŒ ์ •์˜ยทํ™œ์šฉ๋˜๋Š”์ง€ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค.


1๏ธโƒฃ Observer์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ

public protocol ObserverType {
    associatedtype Element
    func on(_ event: Event<Element>)
}
  • Element: ์ „๋‹ฌ๋ฐ›์„ ๋ฐ์ดํ„ฐ ํƒ€์ž… <T>

  • Event<Element>: .next(Element), .error(Error), .completed 3์ข… ์ค‘ ํ•˜๋‚˜

์‹ค์ œ ์•ฑ์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„ ํด๋กœ์ € ๊ธฐ๋ฐ˜ ๊ตฌ๋…(subscribe)์œผ๋กœ Observer๋ฅผ ์•”๋ฌต์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋ฏ€๋กœ, ์ง์ ‘ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•  ์ผ์€ ๋“œ๋ญ…๋‹ˆ๋‹ค.


2๏ธโƒฃ subscribe ๋ฉ”์„œ๋“œ 4์ด์‚ฌ

๋ฉ”์„œ๋“œ ์‹œ๊ทธ๋‹ˆ์ฒ˜
์‚ฌ์šฉ์ฒ˜
๋น„๊ณ 

subscribe(onNext:)

๊ฐ’๋งŒ ์ฒ˜๋ฆฌ

์ฃผ๋กœ UI ๋ฐ”์ธ๋”ฉ ๊ฐ„๋‹จ ์ฒ˜๋ฆฌ

subscribe(onNext:onError:)

๊ฐ’ + ์—๋Ÿฌ

๋„คํŠธ์›ŒํฌยทDB ๋“ฑ ์‹คํŒจ ๊ฐ€๋Šฅ์„ฑ

subscribe(on:) (Full)

Event<T> ์ง์ ‘ ๋ถ„๊ธฐ

๊ณ ๊ธ‰ ๋กœ๊น…ยท๋ชจ๋‹ˆํ„ฐ๋ง

bind(to:)

UI ์ปดํฌ๋„ŒํŠธ ๋ฐ”์ธ๋”ฉ

์ž๋™ MainScheduler, ์—๋Ÿฌ ์ „๋‹ฌ X

// ๊ฐ’๋งŒ ํ•„์š”ํ•  ๋•Œ
button.rx.tap
    .subscribe(onNext: { print("Tapped!") })
    .disposed(by: bag)

// ์—๋Ÿฌ๋„ ์บ์น˜
fetchPosts()
    .subscribe(onNext: { print($0) },
               onError: { print("โŒ", $0) })
    .disposed(by: bag)

3๏ธโƒฃ AnyObserver & Binder (์ปค์Šคํ…€ Observer)

๐ŸŽ›๏ธ AnyObserver

์ž„์˜์˜ ํด๋กœ์ €๋ฅผ Observer๋กœ ๋ž˜ํ•‘ํ•  ๋•Œ ์‚ฌ์šฉ

let labelObserver: AnyObserver<String> = AnyObserver { event in
    switch event {
    case .next(let text): label.text = text
    case .error(let err): print(err)
    case .completed: break
    }
}

Observable.just("Hello")
    .subscribe(labelObserver)

๐Ÿช„ Binder

UI ์ „์šฉ. MainScheduler์—์„œ ์‹คํ–‰๋˜๊ณ  ์—๋Ÿฌ๋Š” ์ž๋™ ๋ฌด์‹œ(์ „ํŒŒ ์•ˆ ํ•จ)

extension Reactive where Base: UILabel {
    var highlighted: Binder<Bool> {
        Binder(base) { label, active in
            label.isHighlighted = active
        }
    }
}

someBoolStream
    .bind(to: label.rx.highlighted)
    .disposed(by: bag)

4๏ธโƒฃ Scheduler & Threading ์ฃผ์˜

  • Observer๊ฐ€ ์‹คํ–‰๋˜๋Š” ์Šค๋ ˆ๋“œ๋Š” ์ง์ „์— ํ˜ธ์ถœ๋œ observe(on:) ์˜ํ–ฅ.

  • UI ์—…๋ฐ์ดํŠธ๋Š” ๋ฐ˜๋“œ์‹œ MainScheduler์—์„œ!

imageDataStream
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: imageView.setImage)
    .disposed(by: bag)

๐Ÿ’ก DriverยทMainScheduler.instance ์‚ฌ์šฉ์œผ๋กœ UI ์Šค๋ ˆ๋“œ ๋ณด์žฅ & ์—๋Ÿฌ ๋ฌด์‹œ ํŒจํ„ด์ด ์ธ๊ธฐ.


5๏ธโƒฃ Observer ํŒจํ„ด ์‹ค์ „ โ€” ๋กœ๋”ฉ ์ƒํƒœ ๊ด€๋ฆฌ

let loading = PublishSubject<Bool>()

loading
    .bind(to: activityIndicator.rx.isAnimating)
    .disposed(by: bag)

apiRequest()
    .do(onSubscribe: { loading.onNext(true) },
        onDispose:   { loading.onNext(false) })
    .subscribe()
    .disposed(by: bag)

do(onSubscribe:onDispose:)๋Š” ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ํ›…์œผ๋กœ, ์ŠคํŠธ๋ฆผ ์ž์ฒด์—” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.


6๏ธโƒฃ Observer Cheat Sheet

๋ชฉ์ 
์ถ”์ฒœ Observer
ํŠน์ง•

์ผ๋ฐ˜ ๊ฐ’ ์ฒ˜๋ฆฌ

subscribe(onNext:)

๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ

UI ๋ฐ”์ธ๋”ฉ

bind(to:), Binder

์—๋Ÿฌ ๋ฌด์‹œ, MainScheduler ๊ณ ์ •

์ปค์Šคํ…€ ๋กœ๊น…

subscribe(on:) (Event)

๋ชจ๋“  ์ด๋ฒคํŠธ ์„ธ๋ถ€ ํ™•์ธ

์ƒํƒœ ๊ณต์œ 

BehaviorSubject, ReplaySubject (Hot)

๊ตฌ๋… ์ฆ‰์‹œ ์ตœ์‹  ๊ฐ’ ์ „๋‹ฌ


7๏ธโƒฃ Mini Quiz

  1. Binder์™€ AnyObserver์˜ ๋‘ ๊ฐ€์ง€ ์ฐจ์ด์ ์€?

  2. ๋™์ผ Observable์— observe(on: Main) ์—†์ด ๋ฐ”๋กœ subscribeํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ œ ์œ„ํ—˜?

  3. ๋„คํŠธ์›Œํฌ ์š”์ฒญ Observable์—์„œ ๋กœ๋”ฉ ํ† ๊ธ€์„ ๊ตฌํ˜„ํ•  ๋•Œ do(onSubscribe:onDispose:) ๋Œ€์‹  activityIndicator ์˜คํผ๋ ˆ์ดํ„ฐ(๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ) ์‚ฌ์šฉ ์žฅ์ ์€?

์ •๋‹ต
  1. Binder vs AnyObserver

  • Binder๋Š” MainScheduler ๊ฐ•์ œ & ์—๋Ÿฌ๋ฅผ ๋ฌด์‹œ, AnyObserver๋Š” ์ž์œ ๋กœ์šด ์Šค๋ ˆ๋“œ & ์—๋Ÿฌ ์ „๋‹ฌ ๊ฐ€๋Šฅ.

  • Binder๋Š” Reactive extension ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์ƒ์„ฑ, AnyObserver๋Š” ์–ด๋””์„œ๋“  ์‚ฌ์šฉ.

  1. UI ๋ณ€๊ฒฝ์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰ํ•ด ํฌ๋ž˜์‹œ(UIView ์‚ฌ์šฉ ๋น„-main) ์œ„ํ—˜. observe(on: MainScheduler.instance) ๋˜๋Š” bind(to:) ํ•„์š”.

  2. activityIndicator ์˜คํผ๋ ˆ์ดํ„ฐ๋Š” ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ณ  Sync lock ๋ฌธ์ œ๋ฅผ ํ”ผํ•˜๋ฉด์„œ ์ŠคํŠธ๋ฆผ ์ฒด์ด๋‹๋งŒ์œผ๋กœ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ๊ด€๋ฆฌํ•ด ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ๊ฐ์†Œ.


๋‹ค์Œ ํŽ˜์ด์ง€ โ–ถ๏ธ Disposables: ๋ฆฌ์†Œ์Šค ํ•ด์ œ ์ „๋žต์„ ๋” ๊นŠ์ด ํŒŒ๊ณ ๋“ญ๋‹ˆ๋‹ค. ๐Ÿš€

Last updated