LoginSignup
3
5

More than 5 years have passed since last update.

RxSwiftでonErrorを遅延させる

Last updated at Posted at 2018-06-24

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)
3
5
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5