Edited at

RxSwiftでonErrorを遅延させる

More than 1 year has passed since last update.

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)