I have a favorite Button, the button isSelected
changed by the network data and tap the button. When the isSelected by tap the button, it need to request the favorite or unfavorite API, but when it changed by the network data, it is not need to request api.
It is my code, when the isSelected changed it always request the api.
// in viewmodel
isFavorite = selectedVideo
.map { $0.isFavorite ?? false }
.flatMapLatest({ favorite in
onTapFavorite.scan(favorite) { acc, _ in !acc }.startWith(favorite)
})
.distinctUntilChanged()
// when subscribe
Observable.combineLatest(viewModel.isFavorite, viewModel.selectedVideo)
.flatMapLatest({ (isFavorite, video) in
if isFavorite {
return APIService.favoriteVideo(videoId: video.videoId)
} else {
return APIService.unfavoriteVideo(videoId: video.videoId)
}
})
.subscribe(onNext: { _ in
}).disposed(by: disposeBag)
2
Answers
You have two features, so you should have two Observable chains…
The server update chain looks like this:
And is bound like this:
For the isSelected property, use a different Observable chain:
which is bound like this:
In reviewing the requirements for this question. I see there can be a lot of complexity when taking errors into account. I decided to give an answer that uses my Cause-Logic-Effect tools to fully flesh out the answer including error conditions:
The following code takes care of all of the following:
selectedVideo
) it updates the state of the button without making a network call.api
object notifies error subscribers of the error (in case you want to put up an alert or something letting the user know the error occurred.)The above is how I would write the code if it was in a project I was working on. Likely, I would pull the closures out into separate functions that I could test.