简体   繁体   English

如何使用 RxSwift 在订阅中执行订阅?

[英]How to perform subscription within subscription using RxSwift?

Currently I have the following working code:目前我有以下工作代码:

    mainView.saveButton.rx.tap.bind { [weak self] in
        if let self = self {
            // start indicator
            self.viewModel.save() // Completable
                .subscribe(onCompleted: { [weak self] in
                    // completed
                }, onError: { error in
                    // error
                })
                .disposed(by: self.disposeBag)
        }
    }.disposed(by: disposeBag)

But I know it is not a good approach (due to nested subscriptions), so I am trying to create working equivalent (now with no success):但我知道这不是一个好方法(由于嵌套订阅),所以我正在尝试创建等效的工作(现在没有成功):

    mainView.saveButton.rx.tap
        .do(onNext: { [weak self] in
            // start indicator
        })
        .flatMapFirst { _ in
            self.viewModel.save() // Completable
        }
        .subscribe(onError: { error in
            // error
        }, onCompleted: { [weak self] in
            // completed
        })
        .disposed(by: disposeBag)

Subscribe closure is not calling at all.订阅关闭根本没有调用。 Why?为什么?

The flatMap won't complete until its source (the button tap) completes. flatMap在其源(按钮点击)完成之前不会完成。 It can't because it has to be ready if the user taps the button again.不能,因为如果用户再次点击按钮,它必须准备好。

The most common way to fix this would be to have your save() function return a Single<Void> instead of a Completable .解决此问题的最常见方法是让您的save() function 返回Single<Void>而不是Completable If you don't want to (or can't) do that, then you can use andThen to send an event on completion.如果您不想(或不能)这样做,那么您可以使用andThen在完成时发送事件。

Also, you don't want an error to escape the flatMap because that will break the button tap.此外,您不希望出现错误来逃避 flatMap,因为这会破坏按钮点击。 This means you need to catch any errors and convert them to next events within the closure .这意味着您需要catch任何错误并将它们转换为闭包中的下一个事件。 You can do that with materialize() or catch and use a dedicated subject.您可以使用materialize()catch并使用专用主题来做到这一点。 (Check out my ErrorRouter for example.) (例如,查看我的ErrorRouter 。)

Something like this:像这样的东西:

let errorRouter = ErrorRouter()
let saveSuccessful = mainView.saveButton.rx.tap
    .flatMap { [viewModel] in
        viewModel.save()
            .andThen(Observable.just(()))
            .rerouteError(errorRouter)
    }

Observable.merge(
    mainView.saveButton.rx.tap.map(to: true),
    saveSuccessful.map(to: false)
)
.bind(onNext: { isIndicatorVisible in
    // handle indicator
})
.disposed(by: disposeBag)

errorRouter.error
    .bind(onNext: { error in
        // handle error
    })
    .disposed(by: disposeBag)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM