RxSwift + UIRefreshControl + MVVMで幸せになる
iOSにはUIRefreshControlというものがあります(twitterでいうところのシュッテしてポンってなるやつ)
あれ結構使うわりにはいちいちpropertyを設定するのが面倒だったので
MVVMを使うこと前提にRxRefreshingControl
というものを作ってしまえば楽じゃねと思い作りました。
import RxSwift import RxCocoa protocol RefreshableModel: class { func refresh() var refreshingState: Driver<Bool> { get } } class RxRefreshControl: UIRefreshControl { private weak var refreshableModel: RefreshableModel? private let disposeBag = DisposeBag() private override init() { super.init() rx.controlEvent(.valueChanged) .asDriver() .drive(onNext: { [weak self] _ in self?.refreshableModel?.refresh() }).disposed(by: disposeBag) } required init?(coder aDecoder: NSCoder) { fatalError("init coder has not been implemented") } convenience init(_ refreshableModel: RefreshableModel) { self.init() self.refreshableModel = refreshableModel } func setupEndRefresingListener(_ listner: @escaping () -> Void) { refreshableModel?.refreshingState .drive(onNext: { [weak self] _ in self?.endRefreshing() listner() }).disposed(by: disposeBag) } }
refreshingControlの役割としてはシュってしたらrefreshのリクエストが走り、responseが会ったらポンってなってほしいだけです。
そのため、VMをRefreshableModelに準拠させ、①refreshの状態をDriverによって流してやること、②refresh時APIを叩くメソッド を用意しといて上げれば
ViewController では
private lazy var refreshControl: RxRefreshControl = { return RxRefreshControl(viewModel) }()
としてrefreshControlをしてrefreshしたいtableView
やcollectionView
に対して.addSubView(refreshControl)
して
もしrefresh時のコールバックを仕込みたければviewDidLoad
などで
refreshControl.setupEndRefreshingListener {
// 任意のコールバック
}
とすれば良くなるわけですね。
これでrefreshが少しは扱いやすくなるかと思います