防止Observabe.error完成并迅速处理

时间:2018-12-27 11:35:28

标签: swift rx-swift moya

我有一个可观察到的(来自网络的请求),并且不想在遇到错误时将其丢弃

我的自定义错误

   enum MyError: Error {
        case notFound
        case unknown
    }

我的网络请求使用Moya

let registerRequest = didTapJoinButton.withLatestFrom(text.asObservable())
            .flatMapLatest { text in
                provider.rx.request(API.register(text: text))
            }
            .flatMapLatest({ (response) -> Observable<Response> in
                let statusCode = response.statusCode

                if statusCode.isSuccessStatus() {
                    return Observable.just(response)

                } else if statusCode.isNotFoundStatus() {
                    return Observable.error(MyError.notFound)

                } else {
                    return Observable.error(MyError.unknown)
                }
            })
            .materialize()
            .share(replay: 1)

看起来很棒。我使用materialize()来防止将可观察的对象置于错误状态

订阅:(如果状态码为200) 一切正常,我得到回应,流没有被处理

   registerEventRequest.subscribe(onNext: { (next) in
            print("NEXT: \(next)")
        }, onError: { (error) in
            print("ERRRRROR ME: \(error)")
        }, onCompleted: {
            print("Completed")
        }) {
            print("Disposed")
        }

但是,如果状态代码类似于404。我得到了预期的错误。但是,嘿,请看控制台日志

NEXT: error(notFound)
Completed
Disposed

它跳到了我期望的NEXT。但是为什么它会完整地处理我的序列。

我的问题是为什么它要处理我的序列以及如何防止这种情况发生?

1 个答案:

答案 0 :(得分:1)

.materialize()不能防止被错误观察到。当Observable发出错误时,它完成并且具体化只是将错误转换为下一个事件。

您需要将实体化放入第一个flatMapLatest中,以防止错误转义flatMap闭包。

该视频可能会有所帮助(注意selectManyflatMap相同)https://channel9.msdn.com/Blogs/J.Van.Gogh/Reactive-Extensions-API-in-depth-SelectMany?term=select%20many&lang-en=true


这是组成Observable的另一种方式:

let registerRequest = didTapJoinButton.withLatestFrom(text.asObservable())
    .flatMapLatest { text in
        provider.rx.request(API.register(text: text))
            .materialize()
    }
    .map { (event) -> Event<Response> in
        switch event {
        case .next(let response) where response.statusCode.isNotFoundStatus():
            return Event.error(MyError.notFound)

        case .next(let response) where response.statusCode.isSuccessStatus() == false:
            return Event.error(MyError.unknown)

        default:
            return event
        }
    }
    .share(replay: 1)

我将materialize()移到了它所在的位置,因此错误不会破坏链条。我也将第二个flatMapLatest换成了简单的map,因为不需要额外的工作。

switch语句也可以这样写:

switch event {
case .next(let response):
    let statusCode = response.statusCode
    if statusCode.isNotFoundStatus() {
        return Event.error(MyError.notFound)
    }
    else if statusCode.isSuccessStatus() {
        return event
    }
    else {
        return Event.error(MyError.unknown)
    }

default:
    return event
}

但是我认为这样做的方法更清洁,因为它降低了封闭件的圈复杂度。


下面是处理注释中引起的关注的代码:

extension ObservableType {
    func flatMapLatestT<T, U>(_ selector: @escaping (T) -> Observable<U>) -> Observable<Event<U>>
        where Self.E == Event<T>
    {
        return self.flatMapLatest { (event) -> Observable<Event<U>> in
            switch event {
            case .next(let element):
                return selector(element).materialize()
            case .completed:
                return .just(Event<U>.completed)
            case .error(let error):
                return .just(Event<U>.error(error))
            }
        }
    }
}

此要点包含一整套用于处理事件的运算符。 https://gist.github.com/dtartaglia/d7b8d5c63cf0c91b85b629a419b98d7e