Thanks to @fimuxd ๐ค
์ฐธ๊ณ ์๋ฃ
https://github.com/ReactiveX/RxSwift
https://github.com/fimuxd/RxSwift
iOSใขใใช่จญ่จใใฟใผใณๅ
ฅ้ – https://peaks.cc/books/iOS_architecture
MVVM
๊ตฌ์กฐ
View (binding) ViewController (input/output) ViewModel (update/notify) Model
1. Model
– UI์ ์๊ด์๋ ์์ํ ๋ก์ง๊ณผ ๋ฐ์ดํฐ.
– View, ViewModel ์ ์์กดํ์ง ์์ (= Model๋ง์ผ๋ก๋ ๋น๋ ๊ฐ๋ฅ)
2. View (ViewController)
– ์ ์ ์ ์กฐ์์ ๋ฐ๊ณ , ํ๋ฉด ํ์๋ฅผ ๋ด๋น.
– View๋ ViewModel๊ฐ ๊ฐ๊ณ ์๋ ์ํ์ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ํ๋ค.
– ViewModel์ด ๊ฐ๊ณ ์๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณต, ์
๋ฐ์ดํธํด์ ๋ฐ์ธ๋ฉํ View๊น์ง ์
๋ฐ์ดํธ
– ViewController
– View์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ฒ๋ฆฌํ๊ณ UI ๊ตฌ์ฑ์์๋ฅผ ๋ฐ์ธ๋ฉ ํ ๋๋ง, ViewModel, View์ ํต์ ํ๋ค.
3. ViewModel
– View์ Model ์ฌ์ด์ ํ๋ฉด ํ์๋ฅผ ์ํ ๋งค๊ฐ์ฒด.
– View์ ํ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋๋ค.
– View์์ ์ด๋ฒคํธ๋ฅผ ๋ฐ๊ณ Model์ ์ฒ๋ฆฌ๋ฅผ ์คํ.
– View์์ ์ด๋ฒคํธ๋ฅผ ๋ฐ์ ์ฒ๋ฆฌํ๊ณ ๊ฐ์ ์
๋ฐ์ดํธ.
– ํ๋ฉดํ์๋ฅผ ์ํ ๋ก์ง๋ฅผ ํจ๊ป ๋ด๋นํ๋ ๊ฒ์ด ViewModel
– MVP์ Presenter์ ๋น์ทํ์ง๋ง, Presenter๋ View์ ์ฐธ์กฐ๋ฅผ ์ ์งํ์ง๋ง MVVM์ ViewModel์ ๋ฐ์ดํฐ ๋ฐ์ธ๋ฉ์ ์ํด ์ํ๋ฅผ ์
๋ฐ์ดํธํ๊ธฐ ๋๋ฌธ์ View์ ์ฐธ์กฐ๊ฐ ํ์ํ์ง ์๋ค.
์ค์ ์์ ์ฐ์ต
1. iOS ์ค๊ณ ํจํด ์์
๐
2. https://github.com/fimuxd/RxSwift, Lecture 23 ์์ ๋ฅผ ์กฐ๊ธ ๋ณ๊ฒฝ
Twitter ๋์ Starwars ์ธ๋ฌผ API๋ก ๋ณ๊ฒฝ.
UITableView, MVVM, CustomCell ๊ตฌํ์ ๋์ผ.
๐
1) ํด๊ฒฐํ์ง๋ง ๊ณ ๋ฏผ๋์๋ ๋ถ๋ถ ๐ค
– refreshControl์ Handling : .endRefreshing ์ ์คํ์ํค๋ ํ์ด๋ฐ
– UITableView : delegate, dataSource, customCell / ๋ฅผ ์ด๋ป๊ฒํด์ผํ๋ !
– peoples๊ณผ reload ์ binding : ์ด๋๊ฑธ ๊ธฐ์ค์ผ๋ก ๋ฐ์ธ๋ฉ์ ํ ๊ฒ์ธ๊ฐ
– URLSession ๊ด๋ จ : request ๊ฒฐ๊ณผ๋ฌผ์ Observable๋ก return์ํค๋๊ฒ ๋์๊ฐ? ์๋๋ฉด ๊ทธ๋ฅ ๋ฐฐ์ด์ผ๋ก? Rx์์กด๋์ ๋ฌธ์ .
2) ๊ณผ์
– VC์ binding์ด ๋๋์๋ง์ ๋ณ๋์ ์ ์ ๋์ ์์ด ๋ฐ๋ก requestํ๊ธฐ ์ํด์๋ ์ด๋ป๊ฒํด์ผ RxSwift์ค๋ฌ์ด ์ฝ๋๊ฐ ๋ ๊น.
3) ๋จธ๋ฆฟ์ ์ ๋ฆฌ๊ฐ ์๋ฒฝํ์ง ์์ ๋ถ๋ถ
– Observable๊ณผ Observer
– Observable<ํ์
>.create ~~~~ ์ด ๋ถ๋ถ์ ์ฐ๋๊ฒ ์ด๋ ต๋ค ใ
ใ
กใ
– Disposable
– Subject VS Observable
– bind VS subscribe : error, next, complete ๋ฅผ ์ฌ์ธํ๊ฒ ํธ๋ค๋งํ ๊ฒ์ธ๊ฐ?
– Drive : UI ์ค์ฌ์ผ๋ก ์ฌ์ฉํ๋ ๋ฏ?
– MainThread ๋์ ์ MainScheduler ์ฌ์ฉํ๊ธฐ. ๊ฐ์ํ๋ ๊ฒ๋!
๋ค์ ํ ๋ฒ ์ง๊ณ ๋์ด๊ฐ๊ธฐ
1. Observable๊ณผ Observer
– Observer = ๊ด์ฐฐ์. Observable = ๊ด์ฐฐ์๋ฅผ ๊ฐ์ ธ event๋ฅผ ๊ตฌ๋
.
– Observer๊ฐ ๋ฐํ์ํจ ์ด๋ฒคํธ๋ค์ Observable์ด ๊ตฌ๋
(subscribe)
– Observable์ด ์ด๋ฒคํธ๋ฅผ ๋ฐฐ์ถํ๋ฉด Observer๊ฐ ๋ฐ์.
2. Subject VS Observable
– Subject = Observable + Observer
– ํ๋์ Observer๋ฅผ ์ฌ๋ฌ ๊ณณ์์ ๊ตฌ๋
ํ์ ๋ ์ฐจ์ด๊ฐ ํฌ์ธํธ !
– Subject : ์ฌ๋ฌ ๊ณณ์์ ๊ตฌ๋
ํด๋ Observer์ ์ด๋ฒคํธ ๊ฐ์ด ๋์ผ. (ๅค๊ตฌ๋
์ : ๋จ์ผObserver)
– ObserverType ์ด๊ธฐ ๋๋ฌธ์ (Observer์ ํน์ฑ) on ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
– Observable : ๊ฐ๊ฐ์ ๊ตฌ๋
์ ๋ํ Observer๊ฐ ์กด์ฌ. (๋จ์ผ๊ตฌ๋
์ : ๋จ์ผObserver)
3. Observable<ํ์
>.create ~~~~ ์ด ๋ถ๋ถ์ ์ฐ๋๊ฒ ์ด๋ ต๋ค ใ
ใ
กใ
public static func create(_ subscribe: @escaping (AnyObserver<Element>) -> Disposable) -> Observable<Element> { return AnonymousObservable(subscribe) }
– subscribe
– @escaping (AnyObserver) -> Disposable
– event๋ฅผ ๋ฐ์์ํค๋ Obsever๊ฐ ์ฃผ์ด์ง๊ณ Disposable์ ๋ฆฌํด์์ผ์ผํ๋ ํด๋ก์ .
/// Represents a disposable resource. public protocol Disposable { /// Dispose resource. func dispose() }
– Disposable
– Disposables : Disposable ์ ์์ฑ.
– Disposable ์ .dispose ๋ฅผ ๊ฐ์ง๊ณ ์๋ค. ์ฆ, Observable ์ ๋ฉ๋ชจ๋ฆฌ์์ ํด์ ์ํค๊ณ ํด์ ํ ์ ์๋๋ก ํด์ค๋ค.
– .dispose : ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํด์ ์ํค๋ ๋ฉ์๋
– DisposeBag์ ๋ด๊ธฐ๊ฒ ๋๋ค. DisposeBag์ด dealloc๋๋ฉด ๊ฐ์ด delloc ๋๋ค.
4. bind VS subscribe : error, next, complete ๋ฅผ ์ฌ์ธํ๊ฒ ํธ๋ค๋งํ ๊ฒ์ธ๊ฐ?
public func bind(to relays: PublishRelay<Element>...) -> Disposable { return bind(to: relays) } public func subscribe(onNext: ((Element) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil) -> Disposable { let disposable: Disposable if let disposed = onDisposed { disposable = Disposables.create(with: disposed) } else { disposable = Disposables.create() } #if DEBUG let synchronizationTracker = SynchronizationTracker() #endif let callStack = Hooks.recordCallStackOnError ? Hooks.customCaptureSubscriptionCallstack() : [] let observer = AnonymousObserver<Element> { event in #if DEBUG synchronizationTracker.register(synchronizationErrorMessage: .default) defer { synchronizationTracker.unregister() } #endif switch event { case .next(let value): onNext?(value) case .error(let error): if let onError = onError { onError(error) } else { Hooks.defaultErrorHandler(callStack, error) } disposable.dispose() case .completed: onCompleted?() disposable.dispose() } } return Disposables.create( self.asObservable().subscribe(observer), disposable ) }
– .bind : error๋ฅผ ๋ณ๋๋ก ํธ๋ค๋ง ํ์ง ๋ชปํจ.
– .subscribe : onError ์์ ํธ๋ค๋ง ๊ฐ๋ฅ.
5. Drive : UI ์ค์ฌ์ผ๋ก ์ฌ์ฉํ๋ ๋ฏ?
– RxCocoa ์์ ์ ๊ณต๋จ.
– Driver : UI์์ ์ง๊ด์ ์ผ๋ก ์ฌ์ฉ. MainScheduler์์ ์คํ๋๋ค.
– Observable ์ MainScheduler ์์์ ์คํ์ด ๋ณด์ฅ๋์ง ์๋๋ค.
– Observable์ .subscribe๋ Driver์ .drive
– .drive์์๋ onError๊ฐ ์ ๊ณต๋์ง ์๋๋ค.
– .asDriver : Observable ์์ Driver๋ก ๋ณํ
6. MainThread ๋์ ์ MainScheduler ์ฌ์ฉํ๊ธฐ. ๊ฐ์ํ๋ ๊ฒ๋!
– UI ์ค์ฌ์ ๊ตฌ๋
์ ๊ฒฝ์ฐ์๋ 5์ Driver๋ฅผ ํ์ฉํ๋๊ฒ ์ค์ !
public func observeOn(_ scheduler: RxSwift.ImmediateSchedulerType) -> RxSwift.Observable<Self.Element> // ์ฌ์ฉ ์. let observable = Observable<Int>.just(1) observable.observeOn(MainScheduler.instance)
– ์์ ์ฝ๋์ฒ๋ผ MainScheduler ๋ฅผ ์ง์ ํ๋ ๊ฒ๋ ๋ฌผ๋ก ๊ฐ๋ฅ.
– Custom Scheduler๋ ์ง์ ํ ์ ์๊ณ ์๋ค๊ฐ๋คํ๋๊ฒ๋ ๊ฐ๋ฅํ๋ค.
– Scheduler ๊ฐ Thread๋ผ ์๊ฐํ๋ฉด ์ฃ ํ
[…] ์ด์ ๊ธ ์์ ๋ง๋ RxStarwars ํ๋ก์ ํธ์์ RxTest๋ฅผ ์ฌ์ฉํ Unit Test๋ฅผ ์ถ๊ฐํด๋ณด๊ฒ ์ต๋๋ค๊ณ ๊ณ ์ฝ ~~~ ! ๐๐๐ […]
์ข์์์ข์์