将Observable赋值给外部属性后无订阅事件,原因何在?
问题原因分析与解决方案
这问题我之前帮人排查过好多次,核心出在你对RxSwift里冷Observable的特性和实例替换逻辑的理解上,咱们一步步拆解:
为什么订阅outsideStream收不到事件?
1. 冷Observable的实例不共享特性
你在execute()里创建的internalStream属于冷Observable(比如Observable.create、interval、just这类创建的都是冷序列)。冷Observable的核心特点是:
- 每一次订阅都会触发全新的序列执行流程
- 不同订阅者之间的序列完全独立,数据不共享
更关键的是,你每次调用execute()都会生成一个全新的internalStream实例,然后把outsideStream指向这个新实例。如果你的订阅操作是在第一次赋值前完成的,那订阅的是最初的nil或者旧的实例,新实例的事件根本传不到旧订阅者那里。
2. 成员属性是“替换”而非“转发”
你直接把outsideStream赋值为新的internalStream,这相当于每次execute()都给outsideStream换了一个全新的数据源,但之前的订阅者绑定的是旧的数据源对象。就像你一开始订阅了A频道,后来把频道换成了B,但你的接收器还插在A上,自然收不到B的信号。
正确的解决方案:用Subject做事件转发
Subject是RxSwift里的“万能桥梁”——它既是Observable(可以被订阅)又是Observer(可以接收事件),完美适配这种需要多次发射不同来源事件的场景。具体实现如下:
import RxSwift class TryOut { // 用PublishSubject作为对外的流(根据需求也可以选BehaviorSubject) let outsideStream = PublishSubject<Int>() private let disposeBag = DisposeBag() init() { // 每2秒触发一次execute Observable<Int>.interval(.seconds(2), scheduler: MainScheduler.instance) .subscribe(onNext: { [weak self] _ in self?.execute() }) .disposed(by: disposeBag) } private func execute() { // 这里是你的internalStream,不管它是冷还是热Observable let internalStream = Observable<Int>.just(Int.random(in: 0...100)) // 将internalStream的事件转发到固定的outsideStream internalStream.subscribe(onNext: { [weak self] value in self?.outsideStream.onNext(value) }) .disposed(by: disposeBag) } } // 使用示例 let tryOut = TryOut() tryOut.outsideStream.subscribe(onNext: { value in print("收到事件:\(value)") }) .disposed(by: DisposeBag())
补充说明
- 如果需要让新订阅者能收到最近一次的事件,可以把
PublishSubject换成BehaviorSubject(需要初始化一个默认值,比如BehaviorSubject(value: 0))。 - 这样
outsideStream是一个固定不变的实例,所有订阅者都绑定到它上面,每次execute()生成的事件都会通过它转发出去,再也不会出现订阅失效的问题。
内容的提问来源于stack exchange,提问作者Lamour
相关产品推荐
相关产品推荐

