RxSwift(3.4.1) - Error Handling Operators

错误在任何的应用中都上不可避免的。而且,没有人能够保证应用从来不出现错误,所以我们经常需要一些错误的处理机制。

应用中的一些普遍错误情况


无网络连接(No internet connection)
这是常见的情况。如果应用需要网络连接来获取和处理数据,但是设备并未连接网络,那么就需要能够检测这种情况并且做出合理的响应和反馈。

无效输入(Invalid input)
有时候会需要一定格式的输入,但是用户可能输入完成不一样的内容。比如:在我们的app中有一个输入用户号码的textfield,但是用户忽略了输入的要求,输入的是字母而不是数字。这就是一个典型常常遇到的问题。

API错误和HTTP错误(API error or HTTP error)
API出现错误的情况很多,例如:对于HTTP错误,返回码为400-500,或者错误的返回。

在RxSwift中,错误处理是框架的一部分,错误处理操作符帮助我们获取来自观察者序列的错误通知,能够有两种方式:
catch:使用默认值处理错误(Recover from the error with a default value)
retry:重新尝试几次或者无限制次数(Retry for a limited (or unlimited!) number of times)

捕获和处理错误

catchError

最基本的方式就是使用catch,catch操作符的工作非常相似于swift中的do-try- catch结构。当观察者序列被执行,如果出现了错误,那么返回一个事件包裹该错误。在RxSwift中,有两个主要的操作符捕获错误,第一个是catchError

 public func catchError(_ handler: @escaping (Error) throws -> RxSwift.Observable<Self.E>) -> RxSwift.Observable<Self.E>



这是一个一般的操作符,使用闭包作为参数并且给予机会返回一个完全不同的观察者序列(observable),由返回的观察者序列来终止。如果你并不知道哪里能够使用这个操作方式,思考一下缓存策略,比如:如果观察者序列出现错误,通过该操作符号,我们可以返回之前缓存的值。实现的工作流如下图:


example(of: "catchError") { 
    let disposeBag = DisposeBag()
    //1
    let sequenceThatFails = PublishSubject<String>()
    let recoverySequence = PublishSubject<String>()
    //2
    sequenceThatFails.catchError({ (error) -> Observable<String> in
        print("Error:", error)
        return recoverySequence
    })
    .subscribe({print($0)})
    .addDisposableTo(disposeBag)
    //3
    sequenceThatFails.onNext("0")
    sequenceThatFails.onNext("1")
    sequenceThatFails.onNext("2")
    recoverySequence.onNext("A")
    //4
    sequenceThatFails.onError(TestError.test)
    sequenceThatFails.onNext("3")
    recoverySequence.onNext("B")
    recoverySequence.onNext("C")
}
执行结果和分析:
--- Example of: catchError ---
next(0)
next(1)
next(2)
Error: test
next(B)
next(C)

1: 创建了两个PublishSubject对象
2: 使用catchError操作符捕获sequenceThatFails对象的错误事件,并进行订阅
3: sequenceThatFails正常发送消息事件,但是recoverySequence发送消息无效,因为recoverySequence此时并没有被订阅
4: 发送错误消息事件,catchError获取到错误事件,返回recoverySequence序列,所以后续消息事件操作只对recoverySequence有效


catchErrorJustReturn

第二个操作符就是catchErrorJustReturn,捕获来自观察者序列发送的错误事件

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

它将忽略错误而且仅仅是返回一个预先设置的值。

enum TestError: Error {
    case test
}

example(of: "catchErrorJustReturn") {
    let disposeBag = DisposeBag()
    let sequenceThatFails = PublishSubject<String>()
    //1
    sequenceThatFails
        .catchErrorJustReturn("catch error")
        .subscribe({ print($0)})
        .addDisposableTo(disposeBag)
    //2
    sequenceThatFails.onNext("0")
    sequenceThatFails.onNext("1")
    sequenceThatFails.onNext("2")
    sequenceThatFails.onError(TestError.test)
    //3
    sequenceThatFails.onNext("3")
}
执行结果和分析:
 --- Example of: catchErrorJustReturn ---
 next(0)
 next(1)
 next(2)
 next(catch error)
 completed
 
1:对sequenceThatFails使用捕获错误操作符catchErrorJustReturn,并提供值作为观察者序列的最后值,即获取错误之后,返回改值
2:发送消息,先发送3个正常消息事件,然后发送错误事件,当发送错误事件,由于捕获到错误,所以会打印预先提供的元素值。
3:在一个 Observable发送error消息事件后,你不再能接收到任何它发送的任何值,因为观察者序列已经终止,所以再一次发送消息事件无效。

Retrying Operator

catch errors捕获错误仅仅是RxSwift处理错误的一种方式,我们也可以使用Retrying Operator.当观察者序列发送错误的时候,retry操作符号将被使用,观察者序列将重复的进行操作。注意:retry是重复观察者序列的整个任务。比如下图请求错误:

 Retry opertoe有3个,第一个是最基本的retry()

 public func retry() -> RxSwift.Observable<Self.E>


该操作符将重复观察者序列,并且无限制次数,一直到观察者序列操作成功。着可能创建一个无限序列。例如:如果这里并没有网络,这可能持续使用retry一直到网络可以获取。这是一种粗鲁的方式,而且资源使用太多,所以一般情况下很少使用该方式。

example(of: "retry") { 
    let disposeBag = DisposeBag()
    var count = 1
    //1
    let sequenceThatErrors = Observable<String>.create { observer in
        observer.onNext("0")
        observer.onNext("1")
        observer.onNext("2")
        //2
        if count == 1 {
            observer.onError(TestError.test)
            print("Error encountered")
            count += 1
        }
        //3
        observer.onNext("a")
        observer.onNext("b")
        observer.onNext("c")
        observer.onCompleted()
        //4
        return Disposables.create()
    }
    //5
    sequenceThatErrors
        .retry()
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
执行结果和分析:
--- Example of: retry ---
0
1
2
Error encountered
0
1
2
a
b
c

1: 使用create操作符创建观察者序列sequenceThatErrors
2: 内部判断在count为1的时候,发送错误事件
3: 对sequenceThatErrors使用retry(),并进行订阅,一旦订阅就会立马执行闭包,先发送3个消息事件,然后因为最开始count为1,所以紧接着发送错误事件,后续操作被终止,但是由于我们使用了retry()操作符,所有又会重新开始sequenceThatErrors序列操作,这次同样先发送3个消息事件但是count为2,所以不会执行内部操作,会执行后续消息事件的发送。


第二个是retry(_:)

 public func retry(_ maxAttemptCount: Int) -> RxSwift.Observable<Self.E>

该操作符是上面的一种变体,观察者序列被重复执行有最大的次数限制。我们可以指定重复观察者序列操作的次数。例子跟上面基本一样,改变了判断条件和retry操作符

example(of:"retry maxAttemptCount") {
    let disposeBag = DisposeBag()
    var count = 1
    
    let sequenceThatErrors = Observable<String>.create { observer in
        observer.onNext("0")
        observer.onNext("1")
        observer.onNext("2")
        
        if count < 3 {
            observer.onError(TestError.test)
            print("Error encountered")
            count += 1
        }
        
        observer.onNext("a")
        observer.onNext("b")
        observer.onNext("c")
        observer.onCompleted()
        
        return Disposables.create()
    }
    //1
    sequenceThatErrors
        .retry(3)
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}
执行结果和分析:
--- Example of: retry maxAttemptCount ---
0
1
2
Error encountered
0
1
2
Error encountered
0
1
2
a
b
c

这里因为使用了retry(3),所以在发生错误的情况,会自动重新尝试2次,第一次尝试重新发送序列,count为2,仍然发送错误事件,第二次尝试重新发送消息事件,count为3,尝试成功,所以执行后续操作。

如果我们使用retry(2),将接收到未处理错误信息等内容,结果如下:
--- Example of: retry maxAttemptCount ---
0
1
2
Error encountered
0
1
2
Error encountered
Received unhandled error: /var/folders/wl/c1df1cbx5_l2cf3p0qwp7lqh0000gn/T/./lldb/38168/playground283.swift:551:__lldb_expr_283 -> test

第三个是retryWhen

public func retryWhen<TriggerObservable : ObservableType>(_ notificationHandler: @escaping (RxSwift.Observable<Error>) -> TriggerObservable) -> RxSwift.Observable<Self.E>

这是一个高级的尝试操作,最重要的就是理解notificationHandler,它是TriggerObservable类型。TriggerObservable能够成为一个普通的观察者序列也可以是subject,并且能够被触发和尝试无限次数。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值