현재 뷰컨트롤러가 뷰모델에 직접 데이터를 요청하는 구조 -> viewDidLoad나 viewWillApear 이벤트를 뷰모델에 전달하고 뷰모델이 상태를 변경하면서 데이터를 emit하도록 구조를 변경
MainViewController
override func viewDidLoad() {
super.viewDidLoad()
viewModel.fetchPokemonData()
bind()
}
MainViewModel
final class MainViewModel {
let viewDidLoadSubject = PublishSubject<Void>()
private func bindViewDidLoad() {
viewDidLoadSubject
.subscribe(onNext: { [weak self] in
self?.fetchPokemonData()
})
.disposed(by: disposeBag)
}
...
}
MainViewController
override func viewDidLoad() {
super.viewDidLoad()
viewModel.viewDidLoadSubject.onNext(())
bind()
}
viewDidLoadSubject를 제거하고, 이를 rx.viewDidLoad로 대체해보자
UIViewController+Reactive
import UIKit
import RxSwift
import RxCocoa
extension Reactive where Base: UIViewController {
/// Observable for `viewDidLoad` lifecycle event.
var viewDidLoad: Observable<Void> {
return methodInvoked(#selector(UIViewController.viewDidLoad))
.map { _ in }
}
}
MainViewController
여기도 바꿔보자
MainViewController
mainView.collectionView.rx.contentOffset
.map { [weak self] offset -> Bool in
guard let self = self else { return false }
let contentHeight = self.mainView.collectionView.contentSize.height
let height = self.mainView.collectionView.frame.size.height
return offset.y + height > contentHeight - 100
}
.distinctUntilChanged() // 중복 호출 방지
.filter { $0 } // true인 경우만 통과
.map { _ in () } // Void로 변환
.bind(to: viewModel.loadMoreTrigger)
.disposed(by: disposeBag)