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
์ผ๋ฐ ๊ฐ ์ฒ๋ฆฌ
subscribe(onNext:)
๊ฐ์ฅ ์์ฃผ ์ฌ์ฉ
UI ๋ฐ์ธ๋ฉ
bind(to:)
, Binder
์๋ฌ ๋ฌด์, MainScheduler ๊ณ ์
์ปค์คํ ๋ก๊น
subscribe(on:)
(Event)
๋ชจ๋ ์ด๋ฒคํธ ์ธ๋ถ ํ์ธ
์ํ ๊ณต์
BehaviorSubject
, ReplaySubject
(Hot)
๊ตฌ๋ ์ฆ์ ์ต์ ๊ฐ ์ ๋ฌ
7๏ธโฃ Mini Quiz
Binder
์AnyObserver
์ ๋ ๊ฐ์ง ์ฐจ์ด์ ์?๋์ผ Observable์
observe(on: Main)
์์ด ๋ฐ๋กsubscribe
ํ๋ฉด ์ด๋ค ๋ฌธ์ ์ํ?๋คํธ์ํฌ ์์ฒญ Observable์์ ๋ก๋ฉ ํ ๊ธ์ ๊ตฌํํ ๋
do(onSubscribe:onDispose:)
๋์activityIndicator
์คํผ๋ ์ดํฐ(๋ผ์ด๋ธ๋ฌ๋ฆฌ) ์ฌ์ฉ ์ฅ์ ์?
๋ค์ ํ์ด์ง โถ๏ธ Disposables: ๋ฆฌ์์ค ํด์ ์ ๋ต์ ๋ ๊น์ด ํ๊ณ ๋ญ๋๋ค. ๐
Last updated