RxSwift
์ฝ๋๋ฅผ ์๋ก์ด ๋ฐ์ดํฐ์ ๋ฐ์ํ๋ฉฐ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ฒ ํจ์ผ๋ก์จ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ์ฝ๊ฒ ํ๋๋ก ๋์์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์์ ์ ์๋ก๋ง ๋ณด๋ฉด ์ด๋ ต๋ค. ์ํฉ์ ํตํด ์ดํด๋ณด์
ํ ํ๋ฉด์์ 3๋ฒ ๋คํธ์ํนํ์ฌ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ๋ฒ์ ํํํ๊ณ ์ ํ๋ค๋ฉด ์ด๋ป๊ฒ ์ฒ๋ฆฌํด์ผํ ๊น?
์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ผ๋ก๋ GCD๋ฅผ ์ด์ฉํด์ ์ฒ๋ฆฌํ์ ๊ฒ ๊ฐ๋ค. ํ์ง๋ง ์ด๋ฐ ์ํฉ์์ RxSwift๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋ ์ฝ๊ณ ํจ๊ณผ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
RxSwift๋ฅผ ์์ํ๊ธฐ ์ ์ ์ดํด๋ฅผ ์ํ ๊ธฐ๋ณธ์ ์ธ ๋ด์ฉ์ ์์๋ณด์
๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ ์ฉ์ด๋ค
1. State (Shared mutable state)
iOS ๊ฐ๋ฐ์ ํ ๋ ๋น๋๊ธฐ์ ์ธ State๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ์ด๋ ต๋ค.
ex) ์ข์์ ๊ธฐ๋ฅ์ ๊ตฌํํ ๋ TabBar๋ก ๊ตฌ์ฑ๋์ด ์๋ค๋ฉด ํ ํ๋ฉด์์ ์ข์์๋ฅผ ๋๋ฅด๋ฉด ๋ชจ๋ ํญ์์ isLike์ ์ํ๊ฐ ๋ฐ๋์ด์ผ ํ๋ค.
๊ธฐ์กด์๋ Notification Center๋ฅผ ์ฌ์ฉํด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ง๋ง RxSwift๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ์ฝ๊ฒ ํด๊ฒฐํ ์ ์๋ค.
2. ๋ช ๋ นํํ๋ก๊ทธ๋๋ฐ (Imperative programming)
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupUI()
connectUIControls()
createDataSource()
listenForChanges()
}
- ๊ฐ๊ฐ์ ๋ฉ์๋๋ค์ด ํ๋ ์ผ์ ์ ์ ์๋ค.
- ์ฌ๋ฐ๋ฅธ ์์๋๋ก ๋ฉ์๋๋ค์ด ์๋ํ ์ง ์ ์ ์๋ค.
3. Side Effect
์ด๋ค ๊ฐ์ฒด์ ์ ๊ทผํด์ ๋ณํ๊ฐ ์ผ์ด๋๋ ํ์
connectUIControls()
๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ UI ๊ตฌ์ฑ์์์ ์ฐ๊ฒฐํ๋ค. View์ state๊ฐ ๋ณ๊ฒฝ๋๋ฉด Side Effect๊ฐ ๋ฐ์ํ๋ค.- Side Effect๊ฐ ๋์ ๊ฒ์ ์๋์ง๋ง ์ปจํธ๋กค์ด ๊ฐ๋ฅํด์ผ ํ๋ค.
- ๊ฐ ์ฝ๋์ ๋ํด ์ด๋ค ์ฝ๋๊ฐ Side Effect๋ฅผ ์ผ์ผํค๋์ง, ๋จ์ํ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ถ๋ ฅํ๋์ง ์ ์ ์์ด์ผ ํ๋ค.
4. ์ ์ธ์ ์ฝ๋ (Declarative code)
- ๋ช ๋ นํ ํ๋ก๊ทธ๋๋ฐ์์๋ ์ํ๋ ๋๋ก ์ํ๋ฅผ ๋ณ๊ฒฝํ๋ค.
- ํจ์ํ ์ฝ๋์์๋ Side Effect๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค.
- RxSwift์์๋ ๋ช ๋ นํ ํ๋ก๊ทธ๋๋ฐ๊ณผ ํจ์ํ ์ฝ๋๋ฅผ ๊ฒฐํฉํ์ฌ ๋์ํ๊ฒ ํ๋ค.
- ์ ์ธํ ์ฝ๋(Declarative code)๋ก ๋์์ ์ ์ํ ์ ์๊ณ , RxSwift๋ ๊ด๋ จ ์ด๋ฒคํธ๊ฐ ์์ ๋๋ง๋ค ๋์์ ์คํํ๊ณ ๋ถ๋ณ์ ๊ณ ์ ํ ๋ฐ์ดํฐ ์ ๋ ฅ์ ์ ๊ณตํ๋ค.
- ์ด๋ ๊ฒํ๋ฉด ๋น๋๊ธฐ ์ฝ๋๋ก ์์ ํ ์ ์์ง๋ง, ๋จ์ for๋ฌธ๊ณผ ๋์ผํ ๊ฐ์ ์ ํ๋ค. ๋ถ๋ณ์ ๋ฐ์ดํฐ๋ก ์์ ํ๊ณ ์์ฐจ์ ์ด๊ณ ๊ฒฐ์ ๋ก ์ ์ธ ๋ฐฉ์์ผ๋ก ์ฝ๋๋ฅผ ์คํํ ์ ์๋ค.
5. Reactive Systems (๋ฐ์ํ ์์คํ )
๋ฐ์ํ ์์คํ ์ ๋ค์๊ณผ ๊ฐ์ ํน์ฑ์ ๋๋ถ๋ถ์ ๋ํ๋ด๋ iOS์ฑ์ ํฌํจํ๋ค.
- ๋ฐ์ (Responsive): ํญ์ ๊ฐ์ฅ ์ต์ ์ State๋ฅผ ํ์ํ๋ฉฐ, UI๋ฅผ ์ต์ ์ํ๋ก ์ ์งํ๋ค.
- ๋ณต์๋ ฅ (Resilient) : ๊ฐ๊ฐ์ ํ๋์ ๊ณ ์ ํ๊ฒ ์ ์๋๋ฉฐ ์๋ฌ ๋ณต๊ตฌ๋ฅผ ์ํด ์ ์ฐํ๊ฒ ์ ๊ณตํ๋ค.
- ํ๋ ฅ์ฑ (Elastic) : ์ฝ๋๋ ๋ค์ํ ๋ถํ๋ฅผ ์ฒ๋ฆฌํ๋ฉฐ, ์ข ์ข lazy pull๊ธฐ๋ฐ ๋ฐ์ดํฐ์์ง, Event throtting, ๋ฆฌ์์ค ๊ณต์ ์ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
- ๋ฉ์์ง ๊ธฐ๋ฐ (Message driven) : ๊ตฌ์ฑ์์๋ ๋ฉ์์ง ๊ธฐ๋ฐ ํต์ ์ ์ฌ์ฉํ์ฌ ์ฌ์ฌ์ฉ ๋ฐ ๊ณ ์ ๊ธฐ๋ฅ์ ๊ฐ์ ํ๊ณ , ๋ผ์ดํ ์ฌ์ดํด๊ณผ ํด๋์ค ๊ตฌํ์ ๋ถ๋ฆฌํ๋ค.
RxSwift ๊ธฐ์ด
1. Observable
- ๋ฐ์ดํฐ์ ์ค๋ ์ท์ ์ ๋ฌํ ์ ์๋ ์ด๋ฒคํธ ์ํ์ค๋ฅผ ๋๊ธฐ์ ์ผ๋ก ์์ฑํ๋ ๊ธฐ๋ฅ
- RxSwift๋ Observable์ ํตํด ๊ฐ์ ๋ฐฐ์ถํ ์ ์๊ณ , ์ด ๊ฐ์ ๊ด์ฐฐํ๊ณ ๋ฐ์ํ๋ค.
- ํ๋ ์ด์์ ๊ด์ฐฐ์(Observer)๊ฐ ์ค์๊ฐ์ผ๋ก ์ด๋ค ์ด๋ฒคํธ์ ๋ฐ์ํ๊ณ UI๋ฅผ ์ ๋ฐ์ดํธํ๊ฑฐ๋ ๋ค์ด์ค๋ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ณ ํ์ฉํ ์ ์๊ฒ ํ๋ค.
ObservableType ํ๋กํ ์ฝ
Observable์ ์ธ๊ฐ์ง ์ด๋ฒคํธ๋ง ๋ฐฉ์ถํ ์ ์๋ค.
- next : ์ต์ (๋ค์)๊ฐ์ ์ ์กํ๋ ์ด๋ฒคํธ
- error : Observable์ด ๊ฐ์ ๋ฐฐ์ถํ๋ค ์๋ฌ๊ฐ ๋ฐ์ํ๋ฉด error๋ฅผ ๋ฐ์ํ๊ณ ์ข ๋ฃ์ํค๋ ์ด๋ฒคํธ
- complete : ์ฑ๊ณต์ ์ผ๋ก ์ด๋ฒคํธ ์ํ์ค๋ฅผ ์ข ๋ฃ์ํค๋ ์ด๋ฒคํธ. Observable์ด ๊ฐ์ ๋์ด์ ๋ฐฐ์ถํ์ง ์๋๋ค.
Finite Observable Sequence
1๊ฐ์ ๊ฐ์ ๋ฐฉ์ถํ๊ณ ์ข ๋ฃ๋๋ ์ํ์ค์ ์์ ๋ก ํ์ผ์ ๋ค์ด๋ก๋ํ๋ ์ฝ๋๋ฅผ ์ดํด๋ณด์
- ๋จผ์ ๋ค์ด๋ก๋๋ฅผ ์์ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๊ด์ฐฐํ๋ค.
- ํ์ผ์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ณ ํ์ผ๋ก ์ ์ฅํ๋ค.
- ๋ง์ฝ ๋คํธ์ํน ์ฐ๊ฒฐ์ด ๋๊ธฐ๊ฑฐ๋ ์๊ฐ์ด๊ณผ๊ฐ ๋ฐ์ํ๋ฉด ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
- ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค์ด๋ก๋ํ๋ฉด ์ฑ๊ณต์ผ๋ก ์๋ฃ
API.download(file: "http://filePath....")
.subscribe(onNext: { data in
// ๋ค์ด๋ก๋ํ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ ์ฅ
}, onError: { error in
// ๋ค์ด๋ก๋ ์๋ฌ ๋ฐ์
}, onCompleted: {
// ๋ค์ด๋ก๋ ์๋ฃ
})
- API.download(file:) : ๋คํธ์ํน ๊ฒฐ๊ณผ๋ก Data๋ฅผ ๋ฐฉ์ถํ๋ Observable<Data>๋ฅผ ๋ฆฌํดํ๋ค.
- onNext ํด๋ก์ : next ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ ์ ์๋ค. ์์ ์์๋ ๋ค์ด๋ก๋ํ ๋ฐ์ดํฐ๋ฅผ ํ์ผ๋ก ์ ์ฅํ๊ฒ ๋ ๊ฒ์ด๋ค.
- onError ํด๋ก์ : error ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ ์ ์๋ค. ์์ ์์๋ ์๋ฌ ๋ฐ์ ๋ก๊ทธ๋ฅผ ์ฒ๋ฆฌํ ๊ฒ์ด๋ค.
- onCompleted ํด๋ก์ : completed ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ ์ ์๋ค. ์์ ์์๋ ๋ค์ด๋ก๋ ์ดํ์ ์์ ์ ์ฒ๋ฆฌํ ์ ์๋ค.
Infinite Observable Sequence
๋ค์ด๋ก๋์ฒ๋ผ ์์ฐ์ค๋ฝ๊ฒ ์ข ๋ฃ๋๋ ์ํ์ค์ ๋ฌ๋ฆฌ ๋ฌดํํ ๊ด์ฐฐ๊ฐ๋ฅํ ์ํ์ค๋ ์กด์ฌํ๋ค.
๋ณดํต UI Event๋ ๋ฌดํํ๊ฒ ๊ด์ฐฐ๊ฐ๋ฅํ ์ํ์ค๋ค. ์ฑ์ ๊ธฐ๊ธฐ ๋ฐฉํฅ ๋ณ๊ฒฝ์ ๋ํด ๋์ํ๋ ์ฝ๋๋ฅผ ์์ ๋ก ์ดํด๋ณด์.
RxSwift๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค๋ฉด ์๋์ ๊ฐ์ด NotificationCenter์์ UIDeviceOrientationDidChange์ ๋ํ ์๋ฆผ์ ๋ฐ์ ํด๊ฒฐํ ๊ฒ์ด๋ค.
NotificationCenter.default.addObserver(self,
selector: #selector(rotated),
name: NSNotification.Name.UIDeviceOrientationDidChange,
object: nil)
func rotated() {
if UIDeviceOrientationIsLandscape(UIDevice.current.orientation) {
print("landscape ์ํ")
}
if UIDeviceOrientationIsPortrait(UIDevice.current.orientation) {
print("portrait ์ํ")
}
}
์ด ๋ถ๋ถ์ RxSwift๋ฅผ ์ฌ์ฉํด์ ํด๊ฒฐํด๋ณด์.
UIDevice.rx.orientation
.subscribe(onNext: { current in
switch current {
case .landscape:
print('landscape ์ํ')
case .portrait:
print('portrait ์ํ')
}
})
- UIDevice.rx.orientation : Observable<Orientation>์ ํตํด ๋ง๋ ๊ฐ์์ ์ฝ๋
- orientation์ subscribeํ์ฌ orientation์ ๊ฐ์ด ์์ฑ๋ ๋๋ง๋ค ํ์ฌ์ orientation์ ๋ฐ์ ์ ์๊ณ , ๊ทธ ๊ฐ์ ์ด์ฉํด UI๋ฅผ ์ ๋ฐ์ดํธ ํ ์ ์๋ค.
- ์ด ๊ฒฝ์ฐ, onError, onCompleted๋ ์ ๋ ๋ฐ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์๋ตํ ์ ์๋ค.
2. Operator
- Observable ํด๋์ค์ ๋ฉ์๋
- ObservableType๊ณผ Observable ํด๋์ค์๋ ๋ณต์กํ ๋ ผ๋ฆฌ๋ฅผ ๊ตฌํํ๊ธฐ ์ํด ๋ง์ ๋ฉ์๋๊ฐ ํฌํจ๋์ด ์๋ค. ์ด ๋ฉ์๋๋ค์ Operator๋ผ๊ณ ๋ถ๋ฅธ๋ค.
- Operator๋ ๋น๋๊ธฐ ์ ๋ ฅ์ ๋ฐ์ ์ถ๋ ฅ๋ง ์์ฑํ๊ธฐ ๋๋ฌธ์ ์ฝ๊ฒ ๊ฒฐํฉ ๊ฐ๋ฅํ๋ค.
- Observable์ด ๋ฐฉ์ถํ ๊ฐ์ Rx Operator๋ฅผ ์ ์ฉํ์ฌ ๋ถ์์์ฉ์ ๋ง๋ค ์ ์๋ค.
์์์ ๋ค๋ค๋ ๋ฐฉํฅ์ ํ ์์ ์ Rx Operator๋ฅผ ์ถ๊ฐํด๋ณด์
UIDevice.rx.orientation
.filter { $0 != .landscape }
.map { _ in
return "portrait ์
๋๋ค."
}
.subscribe(onNext: { msg in
print(msg)
})
orientation์ด .lanscape, .portrait๋ฅผ ์์ฑํ ๋๋ง๋ค Rx๋ ๋ฐฉ์ถ๋ ๋ฐ์ดํฐ์ ๊ฐ๊ฐ์ ์ฐ์ฐ์๋ฅผ ์ ์ฉํ๋ค.
- .filter : .landscape๊ฐ ์๋ ๊ฐ๋ง ํต๊ณผ์ํจ๋ค.
- .map : .portrait ๊ฐ์ด ๋ค์ด์จ๋ค๋ฉด map์ "portrait ์ ๋๋ค." ์ถ๋ ฅ์ผ๋ก ๋ณํํ๋ค.
- .subscribe : next ์ด๋ฒคํธ๋ฅผ ๊ตฌํํ๊ณ msg๊ฐ์ ๋ฐ์ printํ๋ค.
3. Schedulers
- Rx์์ DispatchQueue์ ๊ฐ๋ค. ๋ค๋ง ํจ์ฌ ์ฝ๊ณ ๊ฐ๋ ฅํ๋ค.
- RxSwift์๋ ์ฌ๋ฌ Scheduler๊ฐ ์ด๋ฏธ ์ ์๋์ด ์์ด์, ๊ฐ๋ฐ์๊ฐ ๋ฐ๋ก ์์ ์ ์ค์ผ์ฅด๋ฌ๋ฅผ ์์ฑํ ์ผ์ ๋๋ฌผ๋ค.
- ๊ธฐ์กด์๋ GCD๋ฅผ ์ด์ฉํด์ ์ฝ๋๋ฅผ ์์ฑํ๋ค๋ฉด, Scheduler๋ฅผ ์ฌ์ฉํ RxSwift์์๋ ๋ค์๊ณผ ๊ฐ์ด ์๋ํ๋ค.
๋คํธ์ํน์ ์๋ก ๋ค์ด๋ณด์. ๋คํธ์ํน์ ํ์ํ ์์ ์ ์๋์ ๊ฐ๋ค.
- fetch JSON
- process JSON
- display UI
- fetch JSON์ custom Scheduler์์ ๊ตฌ๋๋๋ค.
- ๊ฒฐ๊ณผ๋ก ๋์จ JSON์ Background Concurrent Scheduler์์ processํ๋ค.
- ์ดํ, UI์์ ์ Main Thread Serial Scheduler์์ ์ฒ๋ฆฌ๋๋ค.
RxCocoa
RxCocoa๋ RxSwift์ companion ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, UIkit๊ณผ Cocoa ํ๋ ์์ํฌ ๊ธฐ๋ฐ ๋ชจ๋ ํด๋์ค๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
RxCocoa๋ฅผ ์ฌ์ฉํ์ฌ UIButton์ Tap ์ด๋ฒคํธ๋ฅผ ์ฝ๊ฒ ํ์ธํ ์ ์๋ค.
button.rx.tap.subscribe(onNext: { _ in
print("tap tap")
})
์ด์ธ์๋ UIViewController, UITextView, UIWebView ๋ฑ์ rx๋ฅผ ์ถ๊ฐํ์ฌ ์ฌ์ฉํ ์ ์๋ค.
์ถ์ฒ
https://okanghoon.medium.com/rxswift-1-rxswift-%EC%9E%85%EB%AC%B8-67bfdbd91969