swift - 防止 Observabe.error 完成并快速处理

标签 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() 来防止 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

它跳转到了我预期的 NEXT。但为什么它会抛出 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

关于swift - 防止 Observabe.error 完成并快速处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53944423/

相关文章:

ios - 如何使用 Rxswift 订阅 UISwitch 的值更改控件事件

swift - 无法上传文件 RXSwift Moya 多部分

swift - RxSwift 分页

ios - Swift (iOS) TokenAuthenticationStrategy 为 AlchemyLanguage API 提供了一个 Unresolved 标识符错误

ios - 没有渲染/虚拟内容的 ARKit/SceneKit 截图

ios - 在 iOS swift 中创建一个保存在 Parse 中的计数器

swift - 我可以从 rxSwift map-Function 引发错误吗

ios - Unwind segue——只能声明实例方法@IBAction;和按钮不连接到退出

swift - RxSwift : Set initial value for UIPickerView

swift - 结合绑定(bind)到 tableView 处理网络错误(Moya、RxSwift、RxCocoa)