Reputation: 28164
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)
}
...
Upvotes: 8
Views: 5187
Reputation: 7729
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.
Upvotes: 15