首页 > 解决方案 > 如何使用 RxSwift 在订阅中执行订阅?

问题描述

目前我有以下工作代码:

    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)

但我知道这不是一个好方法(由于嵌套订阅),所以我正在尝试创建等效的工作(现在没有成功):

    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)

订阅关闭根本没有调用。为什么?

标签: iosswiftrx-swift

解决方案


flatMap其源(按钮点击)完成之前不会完成。不能,因为如果用户再次点击按钮,它必须准备好。

解决此问题的最常见方法是让您的save()函数返回 aSingle<Void>而不是 a Completable。如果您不想(或不能)这样做,那么您可以使用andThen在完成时发送事件。

此外,您不希望出现错误来逃避 flatMap,因为这会破坏按钮点击。这意味着您需要catch任何错误并将它们转换为闭包中的下一个事件。您可以使用materialize()catch使用专门的主题来做到这一点。(例如,查看我的ErrorRouter。)

像这样的东西:

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)

推荐阅读