[RxSwift] RxSwift ์ ๋ฌธํ๊ธฐ
์๊ฐ์ด ๊ฐ์๋ก ์ ์ RxSwift๋ ๊ผญ ์์์ผ ํ๋ ํธ๋ ๋์ฃ ~~?ใ ใ
Apple์์๋ Rx+MVVM Base์ธ SwiftUI๋ฅผ ์ฌ์ฉํ๊ธฐ๋ฅผ ์ ์ ์งํฅํ๋ ๊ฒ ๊ฐ๊ณ ์ ใ ใ (๊ฐ์ธ์ ์ธ ์๊ฐใ )
์ ๋ฌด๋ฅผ ํ๋ฉด์๋ ์ ํด๋ณผ ๊ธฐํ๊ฐ ์์ด์, ํผ์ ๋ฐ๋ก๋ผ๋ ํ๋ฒ ๊ณต๋ถํ๋ฉด์ "์ ์ด๋ ๊ฐ๋ ์ ๋๋ ์๊ณ ๊ธฐ๋ณธ์ ๋๋ ์ฌ์ฉํ ์ ์์ด์ผ๊ฒ ๋ค" ํด์ ์์ํด๋ณด๋ ค๊ณ ํด์!! ๐
๊ทธ๋งํผ ์์ด๋ณด๋ฅผ ์ํ ์ ๋ฌธ์ฉ ํฌ์คํ ์ด ๋๊ฒ ์ง๋ง, ํต์ฌ ๊ฐ๋ ์ด๋ ์๋ฆฌ๋ ์์ ์ ํจ๊ป ์์ธํ ๋ค๋ค๋ณผ ์์ ์ด๋ผ ์กฐ๊ธ์ ๊ธด ํฌ์คํ ์ด ๋ ๊ฒ ๊ฐ์ต๋๋ค!! ๐ญ
๊ทธ์น๋ง! ์ด ํฌ์คํ ์ ์ฒ์ฒํ๋ผ๋ ์์ฃผํ์ ๋ค๋ฉด RxSwift์ ๋ํ ๊ฐ๋ ์ด๋ ๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฒ์ ์ตํ์ค ์ ์์๊ฑฐ์์ ๐ง๐ป
RxSwift์ ๋ํด์ ์์๋ณด๊ธฐ ์์ํ๊ธฐ ์ ์, ๊ธฐ๋ณธ์ ์ธ Swift์ ๋ํ ๋ด์ฉ์ ์๊ณ ์๋ค๊ณ ์๊ฐํ๊ณ ์จ๋ณผ๊ฑฐ์์.
๋จผ์ ํ๊ฐ์ง ์ํ์ ์๊ฐ๋๋ฆฌ๋ฉด์ ์์ํด๋ณผ๊ฒ์!
์ด๋ ๊ฒ ์๋จ์ ํ์ด๋จธ๊ฐ ํ๋ฌ๊ฐ๊ณ , LoadJson ๋ฒํผ์ ํตํด ์๋ฒ๋ก๋ถํฐ Json์ ๋ด๋ ค๋ฐ๊ณ ์์ด์.
์ด๋ ๋ค์ด๋ฐ๋ ๋์ ํ์ด๋จธ๊ฐ ๋ฉ์ถ์ง ์๊ณ , User Interaction์ ๋ฐ์ํ๊ธฐ์ํด, ์๋ฒ๋ก๋ถํฐ Json์ ๋ด๋ ค๋ฐ๋ Task๋ background์์ ์ผ์ด๋๊ณ , UI์ ๊ด๋ จ๋ Task๋ ๋ฉ์ธ์ค๋ ๋์์ ์คํํ๊ฒ๋ ๋น๋๊ธฐ์ ์ผ๋ก ์ค๊ณํ์ฃ ~?
func downloadJson(urlString: String, completion: @escaping (String) -> Void) {
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard data != nil, error == nil else { return }
guard let text = String(data: data!, encoding: .utf8) else { return }
completion(text)
}.resume()
}
์๋ง ๋๋ถ๋ถ ์ด๋ฐ์์ผ๋ก ๋ค์ด๋ก๋๊ฐ ์๋ฃ๋๋ฉด completion ํด๋ก์ ํน์ Delegate, Notification ๋ฑ์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ณ , ์ ๋ฌ๋ฐ์ ๋ฐ์ดํฐ๋ก UI ๋ณ๊ฒฝ๊ณผ ๊ด๋ จ๋ ๋ก์ง์ ์คํํ ๊ฑฐ์์.
downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY) { text in
DispatchQueue.main.async {
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
}
}
์ด๋ ๊ฒ ๋ฐ์ดํฐ ๋ค์ด๋ก๋๊ฐ ์๋ฃ๋์์์ ์ธ์งํ๊ณ ๊ทธ ๋ฐ์ดํฐ๋ฅผ completion๊ฐ์ ํด๋ก์ ๋ฅผ ํตํด ๋ฐ์ ๋ค, ํด๋น ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ UI๋ฅผ ์ ๋ฐ์ดํธ ํ๋ Task๋ฅผ ์ํํ๋ ๊ณผ์ ์ ํตํด์ UI๋ฅผ ์ ๋ฐ์ดํธ ํด์ผํ์ฃ .
์ด๋ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ , ์ ๋ฌ๋ฐ๊ณ , UI๋ฅผ ์ ๋ฐ์ดํธํ๋ ์ผ๋ จ์ ๊ณผ์ ์ ๋ฐ๋ก ์ํํ์ง ์๊ณ , ๋ง์ฝ ์ฐ๋ฆฌ๊ฐ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ "๊ด์ฐฐ" ํ๊ณ ์๋๋ฐ ๊ทธ ๋ฐ์ดํฐ๊ฐ "๋ณ๊ฒฝ" ๋ ๋ ์์์ UI๋ฅผ ์ ๋ฐ์ดํธ ํด์ฃผ๋ฉด ๋์ง ์์๊น?
๋ฐ๋ก ์ด๋ฐ ์๊ฐ์ ํ๋ก๊ทธ๋๋ฐ ํจ๋ฌ๋ค์์ด Reactive Programming(๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ) ์ด์์. ๊ทธ๋ฆฌ๊ณ ์ด๊ฑธ Swift์์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋๋ก ์ง์ํด์ฃผ๋๊ฒ RxSwift์์. ์ฆ ๋น๋๊ธฐ๋ก ์๊ธฐ๋ ๊ฒฐ๊ณผ๊ฐ์ completion ํด๋ก์ ๋ฑ์ ํตํด ์ ๋ฌํ๋๊ฒ ์๋๋ผ, ์ด๋ค ๋ฐ์ดํฐ์ ๊ด์ฌ์ ๊ฐ๊ณ ๊ด์ฐฐ(Observe)ํ๊ฒ๋๋ง ํด๋์ผ๋ฉด ์์์ ํด์ค๋ค๋๊ฑฐ์ฃ !
์ฌ๊ธฐ ์ ๊ธฐ๋ฅผ ์ฐพ์๋ด๋, Rx์ ์ ์์ ๋ํด์๋ ๋๋ถ๋ถ ๋น์ทํ ๊ฑฐ์์.
"๊ด์ฐฐ ๊ฐ๋ฅํ ์ํ์ค๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ์ ๋ฐ ์ด๋ฒคํธ ๊ธฐ๋ฐ ํ๋ก๊ทธ๋จ์ ๊ตฌ์ฑํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ"
์~ ๊ทผ๋ฐ ๊ตณ์ด RxSwift๋ฅผ ์จ์ผ๋ผ~? ๊ทธ๋ฅ Swift๋ก๋ didSet์ ์ด์ฉํ๊ฑฐ๋ ๋ฑ๋ฑ ํ์ฉํ๋ฉด ๋์ง์์~?
๋ง์ต๋๋ค!! RxSwift ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ถฉ๋ถํ Reactiveํ๊ฒ๋ ์ฝ๋๋ฅผ ์งค ์ ์์ด์.
๊ทธ๋ฐ๋ฐ ์ฐ๋ฆฌ๊ฐ ๋คํธ์ํฌ ํต์ ์ ์ํด Alamofire๊ฐ์ 3rd-party ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฃ ~? ์์ฌ์ฉํด์~?
๋ต์ ๋น์ฐํ "์ฌ์ฉํ๊ธฐ ํธํ๋๊น" ์ฃ ! URLSession์ผ๋ก ๋คํธ์ํฌ ํต์ ์ ๊ตฌํํด๋ ๋คํธ์ํฌ ํต์ ์ ํ ์ ์์ด์. ๊ทธ์น๋ง ๋๊ตฐ๊ฐ Alamofire๋ฅผ ๋ง๋ค๊ณ , ๋คํธ์ํฌ ํต์ ํ ๋ ์ฐ๊ธฐ ํธํ๊ฒ ๋ง๋ค์ด ๋์๊ธฐ ๋๋ฌธ์, ๊ทธ๊ฑธ ์ฌ์ฉํ๋๊ฒ ๋ฟ์ด์ฃ !
๋ง์ฐฌ๊ฐ์ง๋ก, ๋ฐ๋ก Reactive eXtension Swift (RxSwift)๊ฐ Reactive ํ๊ฒ Swift ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ฝ๊ฒ ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์.
๊ฐ๋จํ๊ฒ ๊ฐ๋ ๊ณผ ์ฉ๋๋ฅผ ํ๋ฒ ์ดํด๋ณด์๋๋ฐ์! ๊ทธ๋ผ ์ด์ RxSwift์ ๋ํด ํ๋ฒ ์์๋ณผ๊น์~?๐ง๐ป
ReactiveX/RxSwift
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
github.com
๋จผ์ RxSwift์ ํต์ฌ ๊ฐ๋ 3๊ฐ์ง์, ๊ฐ๊ฐ์ ์ฌ์ฉ๋ฒ์ ์์๋ณผ๊ฒ์.
Observable
- ์ด๋ฒคํธ๋ฅผ ์๊ฐ ํ๋ฆ์ ๋ฐ๋ผ ์ ๋ฌํ๋ "์ ๋ฌ์"
- ๋น๋๊ธฐ๋ก ๋์ํ๋ ์ผ๋ จ์ ํญ๋ชฉ๋ค์ ๋ํ๋ด๋ "์ํ์ค"
- Observable์ 3๊ฐ์ง ํ์ ์ ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ๊ณ , Observer๊ฐ Observable์ "๊ตฌ๋ "ํ์ฌ ์ด๋ฒคํธ๋ฅผ ์์ ํฉ๋๋ค.
- next : next๋ ๋ค์ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ถํ๋ ์ด๋ฒคํธ, ๊ทธ ๋ฐ์ดํฐ๋ฅผ Observer๊ฐ ์์ (Emission)
- completed : completed๋ ์ํ์ค๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์ข ๋ฃํ๊ณ ๋์ด์ ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ์ง ์์ (Notification)
- error : error๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ฌ ์ํ์ค๋ฅผ ์ข ๋ฃํ๊ณ , ๋์ด์ ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ์ง ์์ (Notification)
์๊น ์์ ์์์์ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ "๊ด์ฐฐ" ํ๋ค๊ณ ํ์ฃ ~? ๋ง ๊ทธ๋๋ก observable ์ "๊ด์ฐฐ๊ฐ๋ฅํ" ์น๊ตฌ์์.
์์์ ๋ค์๋ ์์๋ฅผ ๋๊ฐ์ด Observable์ ์ฌ์ฉํด๋ณผ๊ฒ์.
func downloadJson(urlString: String) -> Observable<String?> {
// ๋น๋๊ธฐ๋ก ์๊ธฐ๋ ๋ฐ์ดํฐ๋ฅผ Observable๋ก ๊ฐ์ธ์ ๋ฆฌํด
return Observable.create { emitter in
let url = URL(string: urlString)
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard error == nil else {
emitter.onError(error!)
return
}
guard data != nil else { return }
guard let text = String(data: data!, encoding: .utf8) else { return }
// ์ค์ ๋ฐ์ดํฐ ์ ๋ฌ
emitter.onNext(text)
// ์๋ฃ ์ฒ๋ฆฌ
emitter.onCompleted()
}
task.resume()
// ์ทจ์๋์์๋ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊ฑด์ง ์ ๋ฌ
return Disposables.create() {
task.cancel()
}
}
}
์ด๋ ๊ฒ Observableํ ์ด๋ค ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๊ฒ ๋ฉ๋๋ค. ๋จ์ํ Observable.create() ๋ฉ์๋๋ก ํ๋์ Observable์ ๋ง๋ค ์ ์์ด์. ์ค์ ๋ก ์ ์๋ฅผ ๋ณด๋ฉด ์ด๋ค Observable์ ๋ฆฌํดํ๋๋ก ๋์ด์๋ค์!
์์ ์ฝ๋๋ฅผ ๋ณด๋ฉด, ๋ฐฉ๊ธ ์ค๋ช ํ๋ 3๊ฐ์ง ์ด๋ฒคํธ๊ฐ ๋ชจ๋ ๋ค์ด๊ฐ ์๋ ๊ฒ ๋ณด์ด์๋์~?
๋จผ์ error๊ฐ ๋ฐ์ํ์ผ๋ฉด onError ์ด๋ฒคํธ๋ฅผ ํตํด ์๋ฌ ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํด์! ํน์ ์ ์์ ์ผ๋ก ๋ญ๊ฐ ์ฒ๋ฆฌ๋์๋ค๋ฉด, onNext ์ด๋ฒคํธ๋ฅผ ํตํด ์ฒ๋ฆฌ๋ ๊ฒฐ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ถํ๊ณ , ์ด ํ์๋ onCompleted ์ด๋ฒคํธ๋ก Observable์ ์ด๋ฒคํธ๋ฅผ ์๋ฃ์ฒ๋ฆฌํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ์ ์๋ฅผ ๋ณด๋ฉด ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด๊ฐ๋ ํด๋ก์ ๊ฐ Disposable์ด๋ผ๋ ๊ฑธ ๋ฆฌํดํ๊ฒ๋ ๋์ด์์ฃ ?
์ด๊ฒ ๋ฐ๋ก return Disposables.create() ์์. ์ด๊ฑด ๋ง์ฝ์ ์ด Observable์ด ์ทจ์๋์์๋ ์ด๋ป๊ฒ ๋์ํ ๊ฑด์ง ์ ๋ฌํ๋๊ฑฐ์์. ์ฆ, ์ฌ๊ธฐ์๋ ๋ง์ฝ ์ทจ์๋๋ฉด ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ Task๋ฅผ ์ทจ์ํ๋ผ๊ณ ํด์ค ๊ฑฐ์์!
์ด์ Observable(๊ด์ฐฐ ๊ฐ๋ฅํ) ๋์์ ๋ง๋ค์ด ์คฌ์ผ๋, ์ด ๋ฐ์ดํฐ๋ฅผ "๊ด์ฐฐ" ํด์ผ๊ฒ ์ฃ ~? ๊ทธ๊ฑธ RxSwift์์๋ "๊ตฌ๋ "ํ๋ค๊ณ ํ๊ณ , subscribeํ๋ค๊ณ ํด์.
downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.debug()
.subscribe { event in
switch event {
case .next(let text):
DispatchQueue.main.async {
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
}
case .completed:
break
case .error:
break
}
}
์ด๋ ๊ฒ ์์์ ๋ง๋ downloadJson Observable์ subscribe(๊ตฌ๋ ) ํด์ฃผ๋๊ฑฐ์์.
๊ทธ๋ฌ๋ฉด ์์์ ์ต์ ๋ฒ๋ธ์ด ๋ฐฐ์ถํ onNext, onCompleted, onError ์ด๋ฒคํธ๋ฅผ ์ฌ๊ธฐ์ ์์ ํ๊ฒ ๋์.
์ฌ๊ธฐ์, subscribe ํด๋ก์ ๋ฅผ ๋ณด๋ฉด self.~ํ๊ณ ํด๋ก์ ๋ด์์ ์๊ธฐ์ฐธ์กฐ๋ฅผ ํ๊ณ ์์ฃ !? ๋ฐ๋ก ์ํ์ฐธ์กฐ๊ฐ ๋ฐ์ํ ์ ์๋ ํฌ์ธํธ์์. ์ฌ์ค ์ฐ๋ฆฌ๋ [weak self] ๋ฅผ ํตํด์ ์๊ธฐ์ฐธ์กฐ๋ก ์ธํ ์ํ์ฐธ์กฐ๋ฅผ ๋ง์์ฃผ๋๋ฐ์~!
์ฌ๊ธฐ์๋ ์ subscribe ํด๋ก์ ๊ฐ complete ์ดํ์ ์ข ๋ฃ๋๋ฉด ํด๋ก์ ๊ฐ ์ญ์ ๋๊ณ , ํด๋ก์ ๊ฐ ์ญ์ ๋๋ฉด ์๊ธฐ์ฐธ์กฐ ํ๋ reference count๋ ๊ฐ์ด ์ค์ด๋ค๊ธฐ ๋๋ฌธ์, ๋ฐ๋ก [weak self]๋ฅผ ์ฌ์ฉํ์ง ์์๋ ๋๋ค๊ณ ํด์. (๊ทผ๋ฐ ์ ๋ ์ธ๋ฏ.. ๐)
์ด ์ต์ ๋ฒ๊ฐ ์ด๋ค ์ด๋ฒคํธ๋ฅผ ๋ฐ์๊ณ , ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ฐ์๋์ง๋ .debug() ๋ฉ์๋๋ฅผ ์จ์ฃผ๋ฉด ์ฝ์์์ ๋ณผ ์ ์์ด์.
์๊น Observable.create()์ ์ ์๋ฅผ ๋ดค์๋, ํด๋ก์ ๋ disposable์ ๋ฆฌํดํ๋๋ก ๋์ด์์์ฃ ?
let disposable = downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.subscribe { event in
...
}
disposable.dispose()
์ด๋ ๊ฒ๋ ์ธ ์ ์์๊ฑฐ์์. dispose() ๋ฉ์๋๋ฅผ ํตํด error, complete ์ด๋ฒคํธ ๋ฐ์ ์ ์๋ ๊ตฌ๋ ์ ์ทจ์ํ ์ ์์ด์.
์ด disposable์ ๋ํด ์กฐ๊ธ๋ง ๋ ์์๋ณผ๊ฒ์.
var disposables: [Disposable] = []
let disposable = downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.subscribe {
...
}
disposables.append(disposable)
๊ทธ๋ผ ์ด๋ ๊ฒ ์ ์ญ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ Disposable ๋ฐฐ์ด์ ๋ง๋ค๊ณ , ๋ญ๊ฐ ๋ค์ด๋ก๋๊ฐ ์งํ์ค์ด์ง๋ง ์ด ํ๋ฉด์ ๋ฒ์ด๋ ๋๋ ๋ค์ด๋ก๋๋ฅผ ๋ฉ์ถ๊ฒ ํ๋ค๋ ๋ฑ์ ์ก์ ์ ํ ๋๋ ์๋์ฒ๋ผ ๊ตฌํํ ์ ์๊ฒ ๋ค์!
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
disposables.forEach { $0.dispose() }
}
๊ทผ๋ฐ ์ด๊ฑด ์ฝ~๊ฐ ๊ท์ฐฎ์ฃ ??ใ ใ ๊ทธ๋์ RxSwift์์ ์ ๊ณตํด์ฃผ๋ DisposeBag ์ด๋ผ๋ ์น๊ตฌ๊ฐ ์์ด์.
๋ง๊ทธ๋๋ก Disposable ๋ค์ ๋ด๊ณ ์๋ ๊ฐ๋ฐฉ์ด์์. ์ด๋ฐ ์น๊ตฌ๋ค์ Sugar API๋๋ Operator๋ผ๊ณ ํ๋๋ฐ, ์๋์์ ์์ธํ ๋ค๋ฃฐ๊ฒ์!
์ด์น๊ตฌ๋ viewWillDisappear์์ ๋ฐ๋ก disposeํด์ฃผ์ง ์์๋, ๋ทฐ์ปจํธ๋กค๋ฌ์ ์ง์ญ๋ณ์๋ก ์ ์ธํด๋์ผ๋ฉด ์ด ํ๋ฉด์ด ์์ด์ง๋ ์๋์ ์ผ๋ก ๊ฐ์ด ์์ด์ ธ์ ๋ฐ๋ก dispose๋ฅผ ํธ์ถํด์ฃผ์ง ์์๋ ๋์.
var disposeBag = DisposeBag()
๊ทธ๋ฆฌ๊ณ ์ต์ ๋ฒ๋ธ์ด ์๊ธธ๋ append ๋์ insert ๋ฉ์๋๋ก ๋ฃ์ด์ค ์ ์์ด์.
disposeBag.insert(disposable)
์.. ๊ทผ๋ฐ ๊ทธ๋ผ ์ต์ ๋ฒ๋ธ์ ๋ง๋ค๋๋ง๋ค disposeBag์๋ค๊ฐ insertํด์ค์ผ๋ผ??
์.๋.์.! ์ด๋ ๊ฒ disposed() ๋ฉ์๋๋ฅผ ํตํด ์ต์ ๋ฒ๋ธ์ ์๊ธธ๋๋ง๋ค ๊ทธ๋ฅ ์ด๋ค disposeBag์์ ๊ด๋ฆฌํ ๊ฑด์ง๋ง ์๋ ค์ฃผ๋ฉด ๋์!
let disposable = downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.subscribe ({
...
})
.disposed(by: disposeBag)
๊ทธ๋ผ, Observable์ ์๋ช ์ฃผ๊ธฐ๋ ์ด๋ ๊ฒ ํํํ ์ ์์ ๊ฒ ๊ฐ์์.
- Create
- Subscribe
- onNext
- onCompleted / onError
- Disposed
์ด๋ ๊ฒ ๋จผ์ ์ฒซ๋ฒ์งธ ํค์๋์ธ Observable์ ๋ํด์ ์ดํด๋ณด์๋๋ฐ์~! ์ด๋ค๊ฑด์ง ์ข ๋๋์ด ์ค์๋์~?
์์ ํ๋ฉด ๋ฑ ์ด๊ฑฐ์์.
Observable(๊ด์ฐฐ๋์)์ ๋ง๋ค๊ณ , Observer๋ ๊ทธ ๊ด์ฐฐ๋์์ subscribe(๊ตฌ๋ ) ํฉ๋๋ค. Observable์ด ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ๋ฉด, Observer๊ฐ ์ด๋ฒคํธ๋ฅผ ์์ ํด์ ์ด๋ค ์ก์ ์ ์ํํฉ๋๋ค.
๊ทธ๋ฐ๋ฐ.. ๋ญ๊ฐ ๊ต์ฅํ ์ฝ๊ฒ ์ธ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ฒ๋ผ ์๊ฐํด๋๊ณ , ์ฌ์ค์ ๋๊ฐ์ด ๋ณต์กํ๋ค? ๋ผ๋ ์๊ฐ์ด ๋์ค๊ฑฐ์์.
์๋น - ์ ์์ ๋๋ค. ๐ง๐ป
์ฌ์ค์ ์ง๊ธ๊น์ง Observable์ ์๋ฆฌ๋ฅผ ์์ธํ๊ฒ ์ค๋ช ํ๊ธฐ ์ํด์ ์์๋ฅผ ํตํด์ ํ๋ฒ ์์๋ณธ๊ฑฐ๊ณ , ์ง๊ธ๋ถํฐ๋ Observable์ ์กฐ๊ธ ๋ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊ฑฐ์์!
์๋ฅผ ๋ค์ด์ "Hello World"๋ผ๋ ๋ฌธ์์ด์ ์ด๋ฒคํธ๋ก ๋ณด๋ด๋ Observable์ด ์์ด์.
func something() -> Observable<String?> {
return Observable.create { emitter in
emitter.onNext("Hello World")
emitter.onCompleted()
return Disposables.create()
}
}
์ง๊ธ๊น์ง ๋๋ก๋ผ๋ฉด.. ์ด ๋จ์ํ ๋ฌธ์์ด์ ํ๋ ๋ณด๋ด๋๋ฐ ์ด๋ฐ ๋ง์ ๊ณผ์ ์ด ํ์ํ์ฃ ~~? ๐ ๊ทธ๋ผ ๊ตณ์ด ์์จ...
๊ทธ๋์~!! RxSwift์์ ์ ๊ณตํด์ฃผ๋ Operator(Sugar API) ์ ๊ฐ๋ ์ด ๋ฑ์ฅํฉ๋๋ค.
func something() -> Observable<String?> {
return Observable.just("Hello World")
}
just๋ ์ ๋ง ๋จ์ํ๊ฒ ํ๋์ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ถํ ๋ ์ฌ์ฉํ ์ ์๋ Operator์์. ๋จ, ํ๋๋ง ๋ฐฐ์ถํ ์ ์์ด์!
๊ทธ๋ผ ๋๊ฐ ์ด์์ ์ด๋ป๊ฒ ํ๋~~?
func something() -> Observable<[String?]> {
return Observable.just(["Hello World", "Hi World"])
}
์ด๋ ๊ฒ! just๋ฅผ ๋๊ฐ์ด ์ฌ์ฉํ๋ [ ] ๋ฐฐ์ด๋ก ์ด๋ฒคํธ๋ฅผ ๋ณด๋ด๋ฒ๋ฆด ์๋ ์์ด์ ใ .ใ ๐
๊ทธ๋ฐ๋ฐ ์ด๋ ๊ฒ ํด๋ฒ๋ฆฌ๋ฉด, ๋ฐฐ์ด ์ ์ฒด๋ฅผ ํ๋ฒ์ ๋ฐ๋ ๋ฐฉ๋ฒ๋ฐ์๋ ์์ด์.
๋ง์ฝ ๋ฐฐ์ด ์์ ๋ฐ์ดํฐ๋ฅผ ํ๋์ฉ ๋ฐ๊ณ ์ถ์ผ๋ฉด ์ด๋ป๊ฒ ํ ๊น์~? ์ด๋ด๋ from์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด ์์ด์.
func something() -> Observable<String?> {
return Observable.from(["Hello World", "Hi World"])
}
์ด๋ฌ๋ฉด ๋ฐฐ์ด ์์ ๋ฐ์ดํฐ๊ฐ ํ๋์ฉ ์ด๋ฒคํธ๋ก ๋ฐ์ดํฐ๊ฐ ๋ฐฐ์ถ๋ ์ ์์ต๋๋ค.
์~~ ๊ทผ๋ฐ ๋ฐฐ์ด์ ์ซ์๋ฐ ์ฌ๋ฌ ๋ฐ์ดํฐ๋ฅผ ์ด๋ฒคํธ๋ก ๋ณด๋ด๋ ค๋ฉด ์ด๋ป๊ฒ ํ๋๋ฐ~~?
์ด๋! of ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
func something() -> Observable<String?> {
return Observable.of("Hello World", "Hi World")
}
์์ฝ
- ํ๋์ ์์๋ฅผ ๋ฐฐ์ถํ๋ ์ต์ ๋ฒ๋ธ ์์ฑ์์๋ just
- ๋ ์ด์์ ์์๋ฅผ ๋ฐฐ์ถํ๋ ์ต์ ๋ฒ๋ธ ์์ฑ์์๋ of
- just์ of๋ ์ธ์๋ฅผ ๊ทธ๋๋ก ๋ฐฐ์ถํ๊ธฐ ๋๋ฌธ์ ๋ฐฐ์ด์ ์ ๋ฌํ๋ฉด ๋ฐฐ์ด์ ๊ทธ๋๋ก ๋ฐฐ์ถ
- ๋ฐฐ์ด์ ์ ์ฅ๋ ์์๋ฅผ ์์ฐจ์ ์ผ๋ก ๋ฐฐ์ถํ๋ ์ต์ ๋ฒ๋ธ ์์ฑ์์๋ from
๊ทธ๋ผ subscribeํ ๋๋ ์ด๋ฐ๊ฒ ์์๊น์~? ๋ฌผ๋ก ์์ต๋๋ค!!
func getSomething() {
something()
.subscribe(onNext: { print($0) },
onError: { err in print(err) },
onCompleted: { print("completed") } )
}
์ด๋ ๊ฒ subscribeํ ๋ ํ๋ผ๋ฏธํฐ๋ก onNext, onError, onCompleted, onDisposed๋ฅผ ์ฌ์ฉํ ์ ์์ด์!
๋ชจ๋ ์ต์ ๋๋ก, ์ ํ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ด๋ฒคํธ์ ๋ํด์๋ง ๊ตฌ๋ ํ๊ฒ๋ ๊ฐ๋ฅํด์.
์๋ฅผ ๋ค์ด์ onNext ์ด๋ฒคํธ๋ง ๋ฐ์์ ๋ญ๊ฐ๋ฅผ ์ฒ๋ฆฌํ๋ ค๋ฉด, ์ด๋ ๊ฒ ํ์ค์ด๋ฉด ์ถฉ๋ถํ๋ต๋๋ค ๐
func getSomething() {
something()
.subscribe(onNext: { print($0) })
}
๊ทธ๋ผ ์์์ ๋ง๋ค์๋ ์์๋ Sugar API๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ ๊ฒ ๊ฐ๋จํ๊ฒ ๋ณํํ ์ ์๊ฒ ์ฃ ~?
@IBAction func loadTapped(_ sender: Any) {
setVisibleWithAnimation(status: true)
downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.subscribe(onNext: { text in
DispatchQueue.main.async {
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
}
})
}
์ด ์ธ์๋ ๋ค์ํ Operator(Sugar API)๊ฐ ์กด์ฌํ๊ณ , ์์ธ ๋ด์ฉ์ ์ฌ๊ธฐ์ ํ์ธํ ์ ์์ด์.
Operator ์ค์๋ Observable์ ๋ง๋ค์ด๋ด๋ ์์ฑ Operator, Observable ๋ฐฐ์ถํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํ๋ Operator, ํด๋น ๋ฐ์ดํฐ๋ฅผ subscribe(๊ตฌ๋ ) ํ๋ Operator ๋ฑ๋ฑ ์์ด์. ์ด Operator๋ RxSwift์ ํต์ฌ ๊ฐ๋ 3๊ฐ์ง์ค ํ๋์์! ๐ ๊ทธ๋ผ ์ฐ์ฐ์์ ๋ํด์ ํ๋ฒ ์์๋ณด๋๋ก ํ ๊ฒ์!
Operator(์ฐ์ฐ์)
์ฐ์ฐ์์ ์ข ๋ฅ๋ ๋ชฉ์ ์ ๋ฐ๋ผ ์์ฑ, ๋ฐ์ดํฐ ๋ณํ, ๋ฐ์ดํฐ ํํฐ๋ง, ๋ฐ์ดํฐ ๋ณํฉ, ์๋ฌํธ๋ค๋ง, ์ ํธ๋ฆฌํฐ ๋ฑ ๋ถ๋ฅ๋ก ๋๋ ์ ธ์.
์ฐ์ฐ์๋ ๋ํ์ ์ผ๋ก observe(on:), Map, Filter, CombineLatest ๋ฑ์ด ์์ด์!
observe(On:) observOn์ด ์ด๋ฆ์ด ๋ณ๊ฒฝ๋์๋ค์. ์ ์ด๋ค ์ค์ผ์ฅด๋ฌ(์ค๋ ๋)์์ ๊ด์ฐฐํ ๊ฑด์ง๋ฅผ ์ ํ ์ ์์ด์. ์ฌ๊ธฐ์ ๋์จ Scheduler๋ ์๋ค๊ฐ ์ข ๋ ์์ธํ๊ฒ ์์๋ณผ๊ฒ์!
์๋ฅผ ๋ค๋ฉด ๋ฐฉ๊ธ ์์์ ๋ดค๋ ์ฝ๋์์ ์ฐ๋ฆฌ๊ฐ DispatchQueue.main.async ์ด๋ ๊ฒ ๋ฉ์ธ์ค๋ ๋์์ ๋์ํ๋๋ก ํด์ฃผ๋๊ฑธ, ๊ทธ๋ฅ observe(on:) ๋ฉ์๋๋ก ํด๊ฒฐํ ์ ์์ด์.
@IBAction func loadTapped(_ sender: Any) {
setVisibleWithAnimation(status: true)
downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.observe(on: MainScheduler.instance)
.subscribe(onNext: { text in
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
})
}
map, filter๋ ์ฐ๋ฆฌ๊ฐ ์๋ ๊ณ ์ฐจํจ์์ ๊ฐ์ ์ญํ ์ ํด์. ์ด 2๊ฐ์ง์ ๋ํ ์์ธํ ์ค๋ช ์ ํจ์คํ ๊ฒ์!
ํน์๋ผ๋ ์ ๋ชจ๋ฅด์๋ฉด ์ด ํฌ์คํ ์ ํ๋ฒ ๋ด์ฃผ์ธ์~!
downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
.map { text in text?.count ?? 0 }
.filter { cnt in cnt > 0 }
.map { "\($0)"}
.observe(on: MainScheduler.instance)
.subscribe(onNext: { text in
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
})
์ด๋ฐ์์ผ๋ก ์ต์ ๋ฒ๋ธ์ด ๋ฐฐ์ถํ ๋ฐ์ดํฐ๋ฅผ map, filter๋ฅผ ํตํด ๊ฐ๊ณตํ๊ณ subscribeํ๊ฒ๋ ํ ์ ์์ด์.
์ด๋ฒ์๋ ๋ณํฉ ์ฐ์ฐ์์ค์ ํ๋์ธ zip์ ๋ํด์ ์๋ฅผ ๋ค์ด๋ณผ๊น์?
๋ณํฉ์ ๋ง๊ทธ๋๋ก ์ฌ๋ฌ๊ฐ์ ์ต์ ๋ฒ๋ธ์ ํฉ์น๋๊ฑฐ์์. Zip์ ๋ ์ต์ ๋ฒ๋ธ์ ์์๋ค์ ํฉ์ณ์ ํ๋์ ๋ฐ์ดํฐ๋ก ๋ณํฉํ ์ต์ ๋ฒ๋ธ์ ๋ง๋๋๋ฐ์~! ์๋ฅผ๋ค๋ฉด ์ด๋ ๊ฒ "Hello"๋ผ๋ ๋ฐ์ดํฐ์ ์ฐ๋ฆฌ๊ฐ ์๋ฒ์์ ๋ด๋ ค๋ฐ์๋ Json ๋ฐ์ดํฐ๋ฅผ ํฉ์ณ์ ์ต์ ๋ฒ๋ธ์ ์์ฑํ๊ฒ ๋์.
let jsonObservable = downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
let helloObservable = Observable.just("Hello")
Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
.observe(on: MainScheduler.instance)
.subscribe(onNext: { text in
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
})
์ข์ ์ ์์์ ์ ๊น ์๊ฐํ ์ฐ์ฐ์ ์ด ์ธ์๋ ์์ฒญ ๋ค์ํ ์ฐ์ฐ์๋ค์ด ์๊ณ , ์ฌ๊ธฐ์ ํ์ธ ๊ฐ๋ฅํ๋ค๊ณ ํ์ฃ ~?
์ข ๋ฅ๋ ๋ง๊ณ , ๋ญ๊ฐ ๋ญ์ง ๋ชจ๋ฅด๊ฒ ๋๋ผ๊ตฌ์!! ๋์ ๊ทธ์ค์ ํ๋๋ฅผ ํ๋ฒ ๋๋ฌ๋ณด๋ฉด, ๋ญ๊ฐ Input๊ณผ Output์ด ์๋ ๋ค์ด์ด๊ทธ๋จ์ด ๋ณด์ผ๊ฑฐ์์. ์ด ๋ค์ด์ด๊ทธ๋จ์ ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ ์ด๋ผ๊ณ ๋ถ๋ฌ์.
์.. ์ค์ผ์ด. ๊ทผ๋ฐ ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ ์ด๊ฑฐ ์ด๋ป๊ฒ ๋ณด๋๊ฑด๋ฐ?
๊ฐ๋จํ ์์ ๋ฅผ ํตํด์ ์กฐ๊ธ์ฉ ์ดํด๋ณผ๊ฒ์!! ๋จผ์ ์์ฑ Operator์ค ํ๋์ธ Just๋ฅผ ๋ณผ๊ฒ์.
๋นจ๊ฐ ํ ์คํธ๋ก ์ด๋ค ๋ชจ์์ด ๋ญ ์๋ฏธํ๋์ง๋ฅผ ํ๋ฒ ์ ์ด๋ดค์ด์!
์ฆ, Just ์ฐ์ฐ์๋ ์ด๋ค ๋ฐ์ดํฐ๋ฅผ ๋ฃ๊ณ Just ์ฐ์ฐ์๋ฅผ ์ ์ฉ์ํค๋ฉด, ์ด๋ค Observable(๊ฐ๋กํ์ดํ)์ด ๋์ค๋๋ฐ, "์ด ์ต์ ๋ฒ๋ธ์ Input์ ๋ฃ์๋ ๋ฐ์ดํฐ์ ๋์ผํ ๋ฐ์ดํฐ๊ฐ ์ด๋ฒคํธ(next)์ ํฌํจ๋๊ณ Completed ์ด๋ฒคํธ๊ฐ ์๋ค." ๋ผ๊ณ ํด์ํ๋ฉด ๋๊ฒ ๋ค์!
์์ง ์ฝ๊ฐ ํท๊ฐ๋ฆฌ์์ฃ ~!? ๋ฐฉ๊ธ ๊ฐ์ด ์ดํด๋ดค๋ From ์ฐ์ฐ์๋ฅผ ๋ณผ๊น์?
์ด๋ค ๋ฐฐ์ด์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ๊ณ From ์ฐ์ฐ์๋ฅผ ์ ์ฉ์์ผฐ๋๋, ์ต์ ๋ฒ๋ธ์ด ๋์๋ค์. ๊ทผ๋ฐ ์ด ์ต์ ๋ฒ๋ธ์ Input์ผ๋ก ๋ฃ์๋ ๋ฐฐ์ด์ ๊ฐ ์์๋ค์ ๋ฐ์ดํฐ ์ด๋ฒคํธ(next)๋ก ํฌํจํ๊ณ , Completed์ด๋ฒคํธ๋ ๊ฐ์ด ์๋ ์ต์ ๋ฒ๋ธ์ด๋ค์!!
์ด์ ์ข ์ด ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ์ ์ด๋ป๊ฒ ๋ด์ผ ํ๋์ง ๋๋ ์ค์๋์~~?
์์ฑ ์ฐ์ฐ์์ ๋ํ๊ฑด ๋ดค์ผ๋, ํํฐ๋ง ์ฐ์ฐ์์ ๋ํด์ ํ๋ฒ ๋ณผ๊ฒ์!
์ด๋ค ์ต์ ๋ฒ๋ธ์ filter ์ฐ์ฐ์์ ๋ฃ์๋๋, ๊ทธ ์กฐ๊ฑด์ ๋ง๋๋ก ํํฐ๋ง๋ ์ต์ ๋ฒ๋ธ์ด ๋์๋ค. ๋ผ๊ณ ํด์ํ ์ ์๊ฒ ์ฃ ?
์ฌ๊ธฐ์ ์์ฑ๊ณผ ํํฐ๋ง ์ฐ์ฐ์์ ์ฐจ์ด ์ค ํ๋๋ Input์ ํํ๊ฐ ๊ทธ๋ฅ ๋ฐ์ดํฐ์ด๊ฑฐ๋, ์ต์ ๋ฒ๋ธ์ด๊ฑฐ๋! ์ด ์ฐจ์ด๊ฐ ์๋ค์!! ๐
์, ์ด์ ํ๊ฐ์ง๋ง ๋ ์ดํดํ์๋ฉด ๋ง๋ธ๋ค์ด์ด ๊ทธ๋จ์ ๋ค ์ดํดํ ์ ์์๊ฑฐ์์.
๋ฐ๋ก observeOn ์ฐ์ฐ์์์! ์ด๊ฑด ์ง๊ธ๊น์ง ํ๊ฒ๋ค์ ํ๋ฒ ์ข ํฉ์ ์ผ๋ก ๋ณผ๊ฒ์!
์.. ์ผ๋จ ๋ณต์กํ๋ค์ ๐ ์๋๋๋ค!! ์ ํ ๋ณต์กํ์ง ์์์. ์ฒ์ฒํ ํด์ํด๋ด ์๋ค.
์์์ ์ ๊น observeOn์ ์ด๋ค ์ฐ๋ ๋์์ ์ฒ๋ฆฌํ ๊ฑด์ง๋ฅผ ์ ํ๋ค๊ณ ํ์ฃ ?
- ์ฒ์์ ํ๋์ ์ฐ๋ ๋์์ ์ํ๋๋ ๋๊ทธ๋ผ๋ฏธ ๋ฐ์ดํฐ ์ด๋ฒคํธ๋ฅผ ๊ฐ์ง ์ต์ ๋ฒ๋ธ์ด ์๋ค์!
- ์ด ์ต์ ๋ฒ๋ธ์ด observeOn(์ฃผํฉ์) ์ฐ์ฐ์๋ฅผ ๋ง๋ ์ฃผํฉ์ ์ฐ๋ ๋์์ ๋์ํ๋ ์ต์ ๋ฒ๋ธ์ด ๋์ด์.
- ๊ทธ๋ฆฌ๊ณ ์ด ์ต์ ๋ฒ๋ธ์ map ์ฐ์ฐ์๋ฅผ ๋ง๋ ๋ค๋ชจ ๋ฐ์ดํฐ๋ก ๋ณํ์ด ๋์์ด์!
- ๊ทผ๋ฐ subscribeOn(ํ๋) ์ ๋ญ๊น์? ๋ฐ๋ก ์ต์ด์ ์ด๋ค ์ฐ๋ ๋์์ ์์ํ ์ง๋ฅผ ์ ํ๋๊ฑฐ์์. ์ด subscribeOn(ํ๋)์ ์ํฅ์ผ๋ก ์ ์ผ ์ฒ์ ์์๋๋ ์ฐ๋ ๋๊ฐ ํ๋์ ์ฐ๋ ๋๊ฐ ๋๋๊ฑฐ์์.
- ๊ทธ๋ฆฌ๊ณ ๋ง์ง๋ง์ผ๋ก observeOn(๋ถํ)์ ๋ง๋, ๊ฒฐ๋ก ์ ์ผ๋ก ๋ถํ์ฐ๋ ๋์์ ๋์ํ๋ ๋ค๋ชจ๋ฐ์ดํฐ(next) ์ด๋ฒคํธ๋ค๊ณผ, completed ์ด๋ฒคํธ๊ฐ ์๋ ์ต์ ๋ฒ๋ธ์ด ์์ฑ๋์์ด์!
์ด๋ ต์ง ์์ฃ !? ๋ชจ๋ฅด๊ณ ๋ณด๋ฉด ๊ต์ฅํ ๋ณต์กํ๊ฒ ๋๊ปด์ง ์ ์๋๋ฐ, ์๊ณ ๋ณด๋ฉด ๊ฐ๋จํด์! ๐ค๐ค๐ค
์ด๋ ๊ฒ ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ์ ํด์ํ๋ ๋ฐฉ๋ฒ๊น์ง ์์๋ดค์ผ๋, ๊ทธ๋ผ ์ด์ ๋ ์ ๋งํฌ์ ์๋ ๋ค์~~~~ํ ์ฐ์ฐ์๋ค์ ๋๋ฌ์ ๋ง๋ธ๋ค์ด์ด๊ทธ๋จ๋ง ๋ณด๋ฉด ์~ ์ด๊ฒ ์ด๋ค ์ฐ์ฐ์๊ตฌ๋. ํ๊ณ ์ดํดํ ์ ์๊ฒ ์ฃ !?
Scheduler
ํต์ฌ ํค์๋ 3๊ฐ์ง์ค 2๊ฐ์ง (Observable, Operator)๋ฅผ ์์๋ดค๊ณ , ์ด์ ๋ง์ง๋ง! Scheduler์ ๋ํด ์์๋ณด๋ ค๊ณ ํด์!
์์์ observe(on:) ์ฐ์ฐ์๋ฅผ ์๊ฐํ๋ฉด์ ์ด๋ค "์ฐ๋ ๋"์์ ๋์ํ๊ฒ ํ ๊ฑด์ง ์ ํ๋ค๊ณ ํ์์ด์. ๊ธฐ์ต๋์๋์?๐
์ฐ๋ฆฌ๋ RxSwift๋ฅผ ์ฐ์ง ์์๋๋ ์ด๋ป๊ฒ ๋ฉํฐ ์ฐ๋ ๋์์ ๋์ํ๋๋ก ํ์์ฃ ~?
๋ฐ๋ก GCD๋ฅผ ์ฌ์ฉํด์์์ฃ ! DispatchQueue, OperationQueue ์ด๊ฒ๋ค์!
GCD๋ฅผ ํตํด ์ด๋ค "ํ"์ ์์ ์ ํ ๋นํ๊ณ , ๊ทธ "ํ"๊ฐ ์ด๋ค "์ฐ๋ ๋" ์์ ์ค์ ๋ก ์์ ์ ์ํํ ์ง๋ ์ ํด์ ์์์ ํด์คฌ์ฃ ?
๋ง์ฐฌ๊ฐ์ง์์. GCD์ ๊ฐ์๊ฒ Scheduler๋ผ๊ณ ์๊ฐํด๋ ๋ ๊ฒ ๊ฐ์์.
let jsonObservable = downloadJson(urlString: Constants.BASE_URL + Constants.API_KEY)
let helloObservable = Observable.just("Hello")
Observable.zip(jsonObservable, helloObservable) { $1 + "\n" + $0 }
.observe(on: MainScheduler.instance)
.subscribe(onNext: { text in
self.contentsTextView.text = text
self.setVisibleWithAnimation(status: false)
})
.disposed(by: disposeBag)
์ฌ๊ธฐ์ .observe(on: MainScheduler.instance) ์ด๋ ๊ฒ ๋ฉ์ธ์ค์ผ์ฅด๋ฌ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ค์ผ์ฅด๋ฌ, ์ปค์คํ ์ค์ผ์ฅด๋ฌ ์ค ์ฉ๋์ ๋ง๊ฒ ์ค์ผ์ฅด๋ฌ์ ๋ฑ๋กํ๊ณ , ์ค์ผ์ฅด๋ฌ๋ ์์์ ์ฐ๋ ๋๋ฅผ ํ ๋นํด์ ์์ ์ ํด์ค๋ค๋๊ฑฐ์ฃ ! ํต์ฌ ๊ฐ๋ ์ด์ง๋ง ์ดํดํ๊ธฐ ์ฝ์ฃ ~~?
์ง๊ธ๊น์ง ๊ธด ์๊ฐ๋์ RxSwift์ ํต์ฌ ๊ฐ๋ ๊ณผ, ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ์ ๋ํด์ ์์๋ณด์๋๋ฐ์!
** ์์
Observable์ ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ถํ๋ ๊ด์ฐฐ๊ฐ๋ฅํ ์ํ์ค์ด๋ค. Observer๋ Observable์ ๊ตฌ๋ (subscribe)ํ๊ณ , Observable์ด ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ๋ฉด ํด๋น Observable์ ๊ตฌ๋ ํ๋ Observer๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ค. Observable์ ์์ฑํ๊ณ , ๊ตฌ๋ ํ๋ ๊ณผ์ ์์ ์ฌ์ฉ์ ํธ๋ฆฌ์ฑ์ด๋ ๊ธฐ๋ฅํ์ฅ์ ์ํด ์ฌ์ฉํ ์ ์๋ ๋ค์ํ Operator(์ฐ์ฐ์) ๊ฐ ์์๊ณ , ๋ฐ์ดํฐ ์์ ํ observeOn๊ณผ Scheduler๋ฅผ ํตํด ์ด๋ค ์ค์ผ์ฅด๋ฌ์์ ์์ ์ ์ํํ ์ง ์ ํ ์ ์์๋ค.
์์ฐ~~ ์งง๊ฒ ์์ฝํ๋ค๊ณ ํด๋ดค๋๋ฐ ์ด์ ์ด ๋ฌธ์ฅ์ด ์ดํด๊ฐ ๊ฐ์๋์!? ๐
์์งํ RxSwift์ ๋ํด์ ๊ณต๋ถํ๊ธฐ ์ ์๋ Observable, ์ํ์ค, ๊ตฌ๋ ๋ฑ๋ฑ ๋ญ๋ง์ด์ผ~ ์ถ์๋๋ฐ, ์ด์ ๋ณด๋ ์ดํด๊ฐ ๋์ฃ ?
์ ๋ ๊ธฐํ๊ฐ ๋๋ฉด RxSwift๋ฅผ ํ์ฉํด์ ์ต์ Toy Project๋, ์ค์ ์ ๋ฌด์์๋ ์ค์ฝ ํ๊ณ ํ์ฉํด๋ณด๋ ค๊ณ ์!!
๊ทธ๋ผ RxSwift๋ฅผ ์ฐ๋ฉด ์ฅ์ ์ ๋ญ๊ณ , ๋จ์ ์ ๋ญ๊น์~?
์ด๋ฒ ํฌ์คํ ์ด ๊ณผํ๊ฒ ๊ธธ์ด์ก์ผ๋.. ๋ค์ ํฌ์คํ ์์ ์ฅ๋จ์ ์ ์ดํด๋ณผ๊ฒ์!!
๊ธด ๊ธ ์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
์ค๋๋ ๋๊ตฐ๊ฐ์๊ฒ ๋์์ด ๋์๊ธธ ๋ฐ๋์ ๐
์ฐธ๊ณ ์๋ฃ : ์ผ๊ณฐ๋์ ์ ํฌ๋ธ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์์ฑ๋ ๊ธ์ ๋๋ค.