ErrorHandling-错误处理

一旦序列里面产出了一个error事件,整个序列将被终止。RxSwift主要有两种错误处理机制:

  • retry - 重试
  • catch - 恢复

retry-重试

retry 可以让序列在发生错误后重试:

// 请求 JSON 失败时,立即重试,
// 重试 3 次后仍然失败,就将错误抛出

let rxJson: Observable<JSON> = ...

rxJson
    .retry(3)
    .subscribe(onNext: { json in
        print("取得 JSON 成功: \(json)")
    }, onError: { error in
        print("取得 JSON 失败: \(error)")
    })
    .disposed(by: disposeBag)

retry(3)就是当发生错误时,就进行重试操作,并且最多重试 3 次。

retryWhen

如果我们需要在发生错误时,经过一段延时后重试,那可以这样实现:

// 请求 JSON 失败时,等待 5 秒后重试,

let retryDelay: Double = 5  // 重试延时 5 秒

rxJson
    .retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
        return Observable.timer(retryDelay, scheduler: MainScheduler.instance)
    }
    .subscribe(...)
    .disposed(by: disposeBag)

这里我们需要用到retryWhen操作符,这个操作符主要描述应该在何时重试,并且通过闭包里面返回的Observable来控制重试的时机:

.retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
    ...
}

闭包里面的参数是Observable<Error>也就是所产生错误的序列,然后返回值是一个Observable。当这个返回的Observable发出一个元素时,就进行重试操作。当它发出一个error或者completed事件时,就不会重试,并且将这个事件传递给到后面的观察者。

如果需要加上一个最大重试次数的限制:

// 请求 JSON 失败时,等待 5 秒后重试,
// 重试 4 次后仍然失败,就将错误抛出

let maxRetryCount = 4       // 最多重试 4 次
let retryDelay: Double = 5  // 重试延时 5 秒

rxJson
    .retryWhen { (rxError: Observable<Error>) -> Observable<Int> in
        return rxError.flatMapWithIndex { (error, index) -> Observable<Int> in
            guard index < maxRetryCount else {
                return Observable.error(error)
            }
            return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)
        }
    }
    .subscribe(...)
    .disposed(by: disposeBag)

我们这里要实现的是,如果重试超过4次,就将错误抛出。如果错误在4次以内时,就等待5秒后重试:

...
rxError.flatMapWithIndex { (error, index) -> Observable<Int> in
    guard index < maxRetryCount else {
        return Observable.error(error)
    }
    return Observable<Int>.timer(retryDelay, scheduler: MainScheduler.instance)
}
...

我们用flatMapWithIndex这个操作符,因为它可以给我们提供错误的索引数index。然后用这个索引数判断是否超过最大重试数,如果超过了,就将错误抛出。如果没有超过,就等待 5 秒后重试。


catchError-恢复

catchError可以在错误产生时,用一个备用元素或者一组备用元素将错误替换掉:

searchBar.rx.text.orEmpty
    ...
    .flatMapLatest { query -> Observable<[Repository]> in
        ...
        return searchGitHub(query)
            .catchErrorJustReturn([])
    }
    ...
    .bind(to: ...)
    .disposed(by: disposeBag)

catchErrorJustReturn。当错误产生时,就返回一个空数组,于是就会显示一个空列表页。你也可以使用catchError,当错误产生时,将错误事件替换成一个备选序列:

// 先从网络获取数据,如果获取失败了,就从本地缓存获取数据

let rxData: Observable<Data> = ...      // 网络请求的数据
let cahcedData: Observable<Data> = ...  // 之前本地缓存的数据

rxData
    .catchError { _ in cahcedData }
    .subscribe(onNext: { date in
        print("获取数据成功: \(date.count)")
    })
    .disposed(by: disposeBag)

参考文档:《Error Handling》

results matching ""

    No results matching ""