6

Hi I am trying to make a UIRefreshControl work with RxSwift. Therefore I am using the Activity Indicator that is in the RxSwift Example.

In my viewModel I have the following function and variable to get my data.

// MARK: - Variables

var data = Variable<[Data]>([])

// MARK: - Public Interface

func getData() {
    let request = Data.readAll()
    _ = request.rxResult().subscribe(onNext: { response in
        self.data.value = response.data
    }, onError: { (Error) in
    }, onCompleted: {
    }, onDisposed: {
    })
}

Then in my view controller I try to bind it to the UIRefreshcontrol and the collection view I have.

let refresher: UIRefreshControl = UIRefreshControl()
let indicator = ActivityIndicator()

    indicator.asObservable()
    .bindTo(refresher.rx.isRefreshing)
    .addDisposableTo(disposeBag)

    let resultObservable = viewModel.data.asObservable()
        .trackActivity(indicator)
        .bindTo(self.collectionView.rx.items(cellIdentifier: reuseCell, cellType: DataCollectionViewCell.self)) {
            row, data, cell in
            cell.configureCell(with: data)
        }
    resultObservable.addDisposableTo(disposeBag)

My question is, what am I missing to make this work? Right now if I start the app nothing happens except a black activity indicator that doesn't stop spinning.

Reshad
  • 2,570
  • 8
  • 45
  • 86

2 Answers2

4

I think you should prefer subscribing in ViewController and add that subscription in that view controller's dispose bag.

The following way I think is the correct way of using ActivityIndicator from RxExamples. following is a pseudo code.

/// ViewController.swift
 import RxSwift
 import RxCocoa
…
 let refreshControl = UIRefreshControl()
 refreshControl.rx.controlEvent(.valueChanged)
        .bind(to:self.viewModel.inputs.loadPageTrigger)
        .disposed(by: disposeBag)
 self.viewModel.indicator
    .bind(to:refreshControl.rx.isRefreshing)
    .dispose(by:disposeBag)
…

/// ViewModel.swift
…
let loadTrigger = PublishSubject<Void>()
let indicator = ActivityIndicator().asDriver()
…
// Assuming rxResult returns Observable<Response>
let req = indicator.asObservable()
    .sample(loadTrigger)
    .flatMap { isLoading -> Observable<Response> in 
         if isLoading { return Observable.empty() }
    return Data.readAll().rxResult()
}
.trackActivity(indicator)
.map { $0.data }
.do(onNext: { [unowned self] data in
    self.data.value = data
})
…
ahsumra
  • 87
  • 10
3
refresher
        .rx.controlEvent(UIControlEvents.valueChanged)
        .subscribe(onNext: { [weak self] in
    //Put your hide activity code here
            self?.refresher.endRefreshing()
            }, onCompleted: nil, onDisposed: nil)
        .disposed(by: disposeBag)

Subscribe an event of refresher(UIRefreshControl)

iOSGhost
  • 182
  • 2
  • 9