RxSwift #06 | Error handing

Managing errors

在应用程序中比较常见的 error 有:

  • No Internet connecting: 无网络连接
  • Invalid input: 无效输入
  • API error or HTTP error: 请求结果返回错误

对于所有接受闭包的操作符,RxSwift 将闭包内抛出的任何错误转化为终止可观察的错误事件。这个错误事件是你可以捕捉并采取行动的。它可以用两种方式处理:

[图片上传失败...(image-dd6875-1639497431330)]

  • Catch: 用一个默认值来从错误中恢复

[图片上传失败...(image-2b2be8-1639497431330)]

  • Retry: 有限次数或者无限次数重试

Throwing errors

URLSession+Rx.swift 文件中,可以看到:

public func data(request: URLRequest) -> Observable<Data> {
    return self.response(request: request).map { pair -> Data in
        if 200 ..< 300 ~= pair.0.statusCode {
            return pair.1
    } else {
            throw RxCocoaURLError.httpRequestFailed(response: pair.0, data: pair.1)
    }
  }
}

这短短六行向我们展示了如何抛出一个错误,具体来说,就是一个定制的错误,这个后面会学到。

注意,在这个闭包中没有 return error,用了 throw 就不需要再使用 return。

Handle errors with catch

最基础的方法是使用 catch, catch 操作符使用起来就好像 Swift 中的 do-try-catch

在 RxSwift 中主要有两种操作符用来 catch errors, 第一个:

func catchError(_ handler:) -> RxSwift.Observable<Self.E>

这是一个通用的操作符;它接受一个闭包作为参数,并提供了返回一个完全不同的可观察变量的机会。如果你不太明白在哪里使用这个选项,可以考虑一个缓存策略,如果观测器出错,就返回一个先前缓存的值。通过这个操作符,你可以实现以下流程:

[图片上传失败...(image-1f60e8-1639497431330)]

在这种情况下,catchError 返回以前可用的值,但由于某种原因,这些值不再可用了。

第二个操作符是:

func catchErrorJustReturn(_ element:) -> RxSwift.Observable<Self.E>

它忽略了错误,只是返回一个预先定义的值。这个操作符比前一个操作符更有局限性,因为它不可能为给定的错误类型返回一个值--对于任何错误都返回相同的值,无论错误是什么。

A common pitfall (一个常见的陷阱)

当一个 Observable error out,error subscription 会被通知,然后所有的订阅都被处理掉。

因此,当一个 Observable error out 时,观察者基本上就被终止了,并且错误之后的任何事件都将被忽略。这是观察者契约的一个规则。

在之前的例子中,如果搜索天气时,抛出了一个 404 error,会发现后面的搜索全部停止工作了,这其实是一个不好的体验。

Catching errors

private var cache = [String: Weather]()
let textSearch = searchInput.flatMap { text in
  return ApiController.shared.currentWeather(city: text)
    .do(onNext: { [weak self] data in
      self?.cache[text] = data
})
    .catchError { error in
      return Observable.just(self?.cache[text] ?? .empty)
    }
}

Retrying on errors

Catching error 只是 RxSwift 中处理错误的一种方式。你也可以用 retry 来处理错误。当使用 retry 操作符时,Observable 出错,Observable 将重复自己。重要的是要记住,重试意味着重复 Observable 内的整个任务。

这也是建议避免在 Observable 内改变用户界面的副作用的主要原因之一,因为你无法控制谁会重试它!

Retry operators

有三种类型的 retry 操作符,第一个:

func retry() -> Observable<Element>

第二个:

func retry(_ maxAttemptCount:) -> Observable<Element>

栗子:

let textSearch = searchInput.flatMap { text in
  return ApiController.shared.currentWeather(city: text)
.do(onNext: { [weak self] data in
      self?.cache[text] = data
    })
    .retry(3)
    .catchError { [weak self] error in
      return Observable.just(self?.cache[text] ?? .empty)
    }
}

如果 Observable 产生错误,它将被连续重试最多三次,即最初的尝试和另外两次尝试。如果它第四次出错,这个错误将不会被处理,执行将转到 catchError 操作符。

Advanced retries

最后一个操作符是 retryWhen, 适用于高级重试情况。这个错误处理操作符被认为是最强大的一个。

func retryWhen(_ notificationHandler:) -> Observable<Element>

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

Creating custom errors

enum ApiError: Error {
  case cityNotFound
  case serverFailure
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容