RxSwift问题:使用flatMap订阅Completable事件无响应的原因与解决
RxSwift中flatMap处理Completable无事件输出的解决方案
问题场景
给定以下代码实现:
func someCompletable() -> Completable { return Completable.create { observer in observer(.completed) return Disposables.create() } } let buttonDidTap = PublishRelay<Void>() // 直接订阅可正常触发onNext事件 buttonDidTap .debug() .subscribe() .disposed(by: disposeBag)
但通过flatMap将其转换为Completable类型后,下游完全收不到任何事件:
buttonDidTap .flatMap { self.someCompletable() } .debug() // 无任何事件触发 .subscribe() .disposed(by: disposeBag)
问题原因
flatMap是针对发射Next事件的Observable设计的操作符,它会订阅内部Observable并转发其Next事件到下游。但Completable的核心特性是仅发射Completed或Error事件,不存在Next事件——当你把Completable传入flatMap时,内部的Completable只会发送Completed信号,不会产生任何Next事件,因此flatMap没有可转发的内容,导致下游订阅完全无响应。
解决方案
根据业务需求,有两种常用处理方式:
方式1:使用专门针对Completable的flatMapCompletable
如果不需要下游接收Next事件,仅需监听Completable的完成/错误状态,直接用flatMapCompletable替代flatMap,它返回Completable类型,订阅时监听对应事件即可:
buttonDidTap .flatMapCompletable { self.someCompletable() } .subscribe( onCompleted: { print("Completable任务完成") }, onError: { error in print("任务执行出错:\(error)") } ) .disposed(by: disposeBag)
方式2:将Completable转换为可发射Next事件的Observable
如果需要下游能接收Next事件以继续链式处理,可通过andThen给Completable追加一个Void类型的Next事件,将其转换为Observable
buttonDidTap .flatMap { self.someCompletable() .andThen(Observable.just(())) // Completable完成后发射一个空值Next事件 } .debug() // 现在可正常收到Next事件,随后触发Completed .subscribe() .disposed(by: disposeBag)
补充方案(嵌套订阅)
若仅需在按钮点击后执行Completable任务,无需链式转发事件,也可直接在buttonDidTap的订阅闭包内处理Completable:
buttonDidTap .subscribe(onNext: { [weak self] in guard let self = self else { return } self.someCompletable() .subscribe(onCompleted: { print("任务执行完成") }) .disposed(by: self.disposeBag) }) .disposed(by: disposeBag)
不过这种嵌套订阅的写法不如链式操作符优雅,推荐优先使用前两种方案。
内容的提问来源于stack exchange,提问作者SH KIM
相关产品推荐
相关产品推荐

