RxSwift:重置DisposeBag无法释放订阅导致重复订阅问题求助
RxSwift重复订阅问题解决方法
问题根源
你在ViewModel初始化时创建的订阅,绑定的是初始化阶段生成的disposeBag实例。后续在bind方法中执行disposeBag = DisposeBag(),只是替换了ViewModel属性的引用,旧的disposeBag因为被之前的订阅持有,不会被销毁,对应的订阅也就不会自动取消,最终导致重复订阅。
具体解决办法
方法一:统一将订阅逻辑移到bind方法中
不要在ViewModel的init方法里做订阅操作,把所有订阅逻辑都放到bind方法内。每次页面复用调用bind时,先重置disposeBag,旧订阅会随着旧disposeBag的销毁被自动取消,再创建新的订阅即可:
class YourViewModel { var disposeBag = DisposeBag() // 定义你的Observable属性 let visibilityObservable: Observable<VisibilityType> init(...) { // 这里仅初始化Observable,不做订阅 visibilityObservable = ... } func bind() { disposeBag = DisposeBag() // 重置后,旧订阅会被销毁 visibilityObservable .skip(1) .distinctUntilChanged() .subscribe(onNext: { [weak self] visibility in self?.delegate?.handleChange(visibility) }) .disposed(by: disposeBag) } }
方法二:用单独的DisposeBag管理初始化时的订阅
如果必须在ViewModel初始化时保留部分订阅逻辑,可以新增一个专门的initDisposeBag来管理这部分订阅,在bind方法里主动重置这个袋子,清空初始化阶段的旧订阅:
class YourViewModel { var disposeBag = DisposeBag() private var initDisposeBag = DisposeBag() // 专门管理初始化时的订阅 init(...) { // 初始化时的订阅绑定到initDisposeBag someObservable .subscribe(...) .disposed(by: initDisposeBag) } func bind() { disposeBag = DisposeBag() initDisposeBag = DisposeBag() // 清空初始化时的旧订阅 // 新的订阅逻辑 visibilityObservable .skip(1) .distinctUntilChanged() .subscribe(onNext: { [weak self] visibility in self?.delegate?.handleChange(visibility) }) .disposed(by: disposeBag) } }
方法三:优化ViewModel与页面的耦合(推荐)
避免在ViewModel中持有页面的delegate,改用Observable输出事件,让ViewController直接订阅ViewModel的输出。这种方式能降低耦合度,也更便于管理订阅生命周期:
class YourViewModel { let visibilityChanged: Observable<VisibilityType> init(...) { visibilityChanged = someObservable .skip(1) .distinctUntilChanged() .share(replay: 1) // 避免重复订阅源Observable } } // 在ViewController中处理订阅 class YourViewController: UIViewController { private let disposeBag = DisposeBag() var viewModel: YourViewModel! override func viewDidLoad() { super.viewDidLoad() viewModel.visibilityChanged .subscribe(onNext: { [weak self] visibility in self?.handleChange(visibility) // 页面自行处理逻辑 }) .disposed(by: disposeBag) } }
内容的提问来源于stack exchange,提问作者swift_dande
相关产品推荐
相关产品推荐

