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

RxSwift中TableView+UIAlertAction数据流异常:首次无值、重复发送求助

问题分析与解决方案

我来帮你捋清楚问题所在,以及怎么修复这些异常:

为什么会出现这些问题?

  • 点Cell就发送数据:你在modelSelected的订阅里直接触发了后续逻辑,但这个订阅会在你点击Cell的瞬间就执行,根本不等你点击Ok按钮。
  • 首次点击Ok无数据:在Ok按钮的回调里,你又重新订阅了modelSelected,但这个新订阅是在点击Cell之后才创建的,已经错过了之前点击Cell产生的事件,自然收不到数据。
  • 数据量递增:每次弹窗你都会新增一个modelSelected的订阅,这些订阅都存在disposeBag里不会自动销毁,导致后续点击时多个订阅同时触发,数据量越来越多。

修正后的代码实现

ViewController 部分

func bindTableView() {
    viewModel.stationItems.bind(to: addTableView.rx.items(cellIdentifier: "addCell", cellType: AddTableViewCell.self)) { (row, item, cell) in
        cell.cellAdd = item
    }.disposed(by: disposeBag)
    
    addTableView.rx.modelSelected(StationItem.self)
        .subscribe(onNext: { [weak self] selectedItem in
            guard let self = self else { return }
            let alert = UIAlertController(title: "Add Station", message: "Do you want to add a station to your favorites?", preferredStyle: .alert)
            
            // Ok按钮直接使用之前选中的item
            let okAction = UIAlertAction(title: "Ok", style: .default) { [weak self] _ in
                guard let self = self else { return }
                self.viewModel.addStationItem(with: selectedItem)
            }
            alert.addAction(okAction)
            
            // 取消按钮用.cancel风格更符合iOS规范
            let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
            alert.addAction(cancelAction)
            
            DispatchQueue.main.async {
                self.present(alert, animated: true)
            }
        }).disposed(by: disposeBag)
    
    viewModel.fetchStations()
}

ViewModel 部分

根据你的需求,有两种实现方式:

方式1:直接通过方法参数传递数据(推荐,更简洁)
// 去掉原来的stationItem Subject,直接用方法接收参数
func addStationItem(with item: StationItem) {
    print("Data: \(item)")
    print("ADD:")
    // 在这里执行添加收藏的逻辑,比如存入本地数据库或请求接口
}
方式2:保留Subject(如果需要在其他地方也传递StationItem数据)
let stationItem = PublishSubject<StationItem>()

init() {
    // 只订阅一次,不要在addStationItem里重复订阅
    stationItem.subscribe(onNext: { data in
        print("Data: \(data)")
    }).disposed(by: disposeBag)
}

func addStationItem(with item: StationItem) {
    // 发送事件到Subject
    stationItem.onNext(item)
    print("ADD:")
}

关键修改点说明

  1. 保存选中的Item:点击Cell时就把selectedItem存下来,Ok按钮回调直接使用这个对象,避免重复订阅modelSelected。
  2. 避免重复订阅:ViewModel的Subject订阅只在初始化时做一次,不会每次调用addStationItem都新增订阅,解决数据递增问题。
  3. 弱引用self:使用[weak self]避免循环引用,防止内存泄漏。
  4. 规范AlertAction风格:取消按钮用.cancel风格,符合iOS的交互设计规范。

这样修改后,就能实现首次点击Ok按钮就传递Cell数据,且仅发送单次数据的需求了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:28:57