阻止 Observabe.error 完成并处置 swift

Prevent Observabe.error complete and dispose swift

我有一个 observable(来自网络的请求)并且不希望在出现错误时处理它

我的自定义错误

   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() 来防止 observable 在错误时被处理

订阅:(如果状态码为 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

它跳转到了我预期的下一步。但是为什么它会抛出 complete 并处理我的序列。

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

.materialize() 不会 防止 observable 在出错时被处置。当 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