美文网首页
RxSwift #06 | Error handing

RxSwift #06 | Error handing

作者: JeremyTechBlog | 来源:发表于2021-12-14 11:10 被阅读0次

    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
    }
    
    

    相关文章

      网友评论

          本文标题:RxSwift #06 | Error handing

          本文链接:https://www.haomeiwen.com/subject/rhmefrtx.html