You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RxSwift自定义视图PublishRelay已接收值但订阅无响应问题咨询

问题可能原因

  • 视图控制器侧的订阅使用了局部DisposeBag:如果订阅时绑定的DisposeBag是方法内的局部变量,方法执行完成后DisposeBag会被回收,对应的订阅会立即被自动取消,自然收不到后续事件。
  • KeyboardView实例被提前释放:如果你的KeyboardView没有被声明为视图控制器的全局存储属性,而是作为局部变量创建添加到视图后没有强引用持有,实例会被ARC提前回收,Relay也会随之销毁,无法触发订阅回调。
  • 订阅时机晚于事件发送:PublishRelay是热可观察序列,只会将订阅之后产生的事件发送给观察者,如果你是在按钮点击触发后才执行订阅逻辑,之前产生的事件不会被响应。
  • 调度规则不匹配:虽然内部按钮事件已经加了observeOn(MainScheduler.instance),但标准ControlEvent要求事件必须在主线程发送,当前的Reactive扩展没有显式保证外层ControlEvent的事件在主线程分发,极端情况下会出现订阅回调不触发的问题。

修复方案

  1. 确保视图控制器侧的订阅绑定到控制器的全局DisposeBag属性,同时全局持有KeyboardView实例:
class ViewController: UIViewController {
    // 声明为全局存储属性,避免被提前回收
    private let disposeBag = DisposeBag()
    private let keyboardView = KeyboardView()

    override func viewDidLoad() {
        super.viewDidLoad()
        // 订阅逻辑在视图加载阶段执行,早于用户点击操作
        keyboardView.rx.buttonTap
            .subscribe(onNext: { action in
                print("收到按键事件: \(action)")
            })
            .disposed(by: disposeBag)
    }
}
  1. 完善Reactive扩展的ControlEvent实现,显式保证主线程调度,符合ControlEvent的官方规范:
extension Reactive where Base: KeyboardView {
    internal var buttonTap: ControlEvent<ActionType> {
        let source = base.buttonTappedRelay
            .asObservable()
            .observe(on: MainScheduler.instance)
        return ControlEvent(events: source)
    }
}
  1. 可选优化:如果需要接收订阅前已经触发的事件,可以把PublishRelay替换为BehaviorRelay,设置默认值即可接收订阅前的最后一次事件。

内容的提问来源于stack exchange,提问作者Andrey Isaev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:00:04