APIの読込中にアニメーションを表示させるために一定時間onNext
,onError
を遅延させたいことがあったのでその実装について
NGな例
// delaySubscriptionを使うことで購読は遅延させられるが
// repository経由のAPI呼び出しそのものが遅くなってしまうので🙅♂️
self.repository.get()
.delaySubscription(1, scheduler: scheduler)
.subscribe(
onSuccess: { [weak self] _ in
self?.state.accept(.success)
}, onError: { [weak self] _ in
self?.state.accept(.fail)
}
).disposed(by: disposeBag)
// API呼び出しを実行しつつonSuccessの呼び出しは遅延されるが
// APIがネットワークエラーなどの時に即時onErrorが呼ばれるてしまうので🙅♂️
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance).take(1).asSingle()
Single.zip(self.repository.get, timer)
.subscribe(
onSuccess: { [weak self] _ in
self?.state.accept(.success)
}, onError: { [weak self] _ in
self?.state.accept(.fail)
}
).disposed(by: disposeBag)
最終的な実装
// Observable#materialize()を使うことでAPI呼び出しの結果を`Observable<RxSwift.Event<Self.E>>`にラップする
// それによりAPI呼び出しが失敗してもonNextに`Error`が流れてくるので、timerの発火を待って処理が行える🙆♂️
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance).take(1)
Observable.zip(timer, self.repository.get().asObservable().materialize()) { $1 }
.dematerialize()
.take(1)
.subscribe(
onNext: { [weak self] _ in
self?.state.accept(.success)
}, onError: { [weak self] _ in
self?.state.accept(.fail)
}
).disposed(by: disposeBag)