I am using the UIRefreshControl
+ Variable
binding to reload data.
It is working, however, the following feels wrong to me:
1) I know there is a rx_refreshing
variable in the RXCocoa
extension, but I am unable to get it to work in this context.
2) I am binding answers (which is a Variable
of array) twice. Once when I load the view controller and again when the UIRefreshControl
is refreshing.
3) The parts where I check for whether the UIRefreshControl
is refreshing or not looks really awkward. It feels like it defeats the purpose of using reactive?
...
let answers: Variable<[Answer]> = Variable([])
override func viewDidLoad() {
loadAnswers()
.shareReplay(1)
.bindTo(answers)
.addDisposableTo(self.disposeBag)
setupRx()
}
func loadAnswers() -> Observable<[Answer]> {
return Network.rxArrayRequest(Spark.Answers)
}
func setupRx() {
rc.rx_controlEvent(.ValueChanged)
.map { _ in !self.rc.refreshing }
.filter { $0 == false }
.flatMapLatest { [unowned self] _ in
return self.loadAnswers()
}
.bindTo(answers)
.addDisposableTo(self.disposeBag)
rc.rx_controlEvent(.ValueChanged)
.map { _ in self.rc.refreshing }
.filter { $0 == true }
.subscribeNext { [unowned self] _ in
self.rc.endRefreshing()
}
.addDisposableTo(self.disposeBag)
}
...
So first of all, It's not actually working. It just seems to be working. In your code, you're actually not waiting for the network request to finish before you call rc.endRefreshing()
. Instead, you're just making the network call and then immediately calling endRefreshing()
.
// `rc.rx_controlEvent(.ValueChanged)` only gets called once,
// when the user pulls down.
rc.rx_controlEvent(.ValueChanged) // user pulled down to refresh
.map { _ in !self.rc.refreshing } // !true -> false
.filter { $0 == false } // false == false
.flatMapLatest { [unowned self] _ in
return self.loadAnswers() // request answers
}
.bindTo(answers)
.addDisposableTo(self.disposeBag)
rc.rx_controlEvent(.ValueChanged) // user pulled down to refresh
.map { _ in self.rc.refreshing } // true -> true
.filter { $0 == true } // true == true
.subscribeNext { [unowned self] _ in
self.rc.endRefreshing() // end refreshing
}
.addDisposableTo(self.disposeBag)
To address concern 1
, you're right, you can use rx_refreshing
to turn off refreshing instead of endRefreshing()
.
To address concern 2
, I don't think the Variable
is necessary or useful, at least in this example. You could still use it though. Also, it's not necessary to loadAnswers()
in two places.
To address concern 3
, yea, you could be simplifying this a lot and using Rx
a bit more.
Here's code that would actually work, use rx_refreshing
, and simplify things a lot:
let initial = Observable<Void>.just(())
let refresh = rc.rx_controlEvent(.ValueChanged).map { _ in () }
let answers = Observable.of(initial, refresh)
.merge()
.flatMapLatest{ _ in self.loadAnswers() }
.shareReplayLatestWhileConnected()
answers
.map { _ in false }
.bindTo(rc.rx_refreshing)
.addDisposableTo(disposeBag)
// also use `answers` to bind to your data source, etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With