2

I have a table view with RxDataSources on which cell items got a remove icon. when cells get dequeued and click on that remove icon, all the previous click events get triggered, thus duplicate tap. Item cell :

 removeImageView.rx.tap().map { _ in indexPath } 
            .bind(to: viewModel.onRemoveItem).disposed(by: cellDisposeBag)

Cell viewmodel:

let onRemoveItem = PublishSubject<IndexPath>()

View controller view model where the cell and ViewModel get bound:

 let vm = ItemViewModel(with: item)
            vm.onRemoveItem.bind(to: self.onRemoveItem).disposed(by: self.rx.disposeBag)

            return SectionItem.item(viewModel: vm)

View Controller:

let dataSource = RxTableViewSectionedReloadDataSource<SectionItem>(configureCell: { dataSource, tableView, indexPath, item in
    switch item {
    case .item(let viewModel):
        let cell = (tableView.dequeueReusableCell(withIdentifier: itemtIdentifier, for: indexPath) as? ItemCell)!
        cell.bind(to: viewModel, at: indexPath)
        return cell
    }
}, titleForHeaderInSection: { dataSource, index in
    let section = dataSource[index]
    return section.title
}  )

output?.items
    .bind(to: tableView.rx.items(dataSource: dataSource))
    .disposed(by: rx.disposeBag)

output?.onRemoveCartIemTapped.distinctUntilChanged() 
    .skip(1)
    .distinctUntilChanged().drive(onNext: { [weak self] (indexPath) in
    print("onRemoveCartIemTapped" + String(indexPath.item))
}).disposed(by: rx.disposeBag)

Console debug:

onRemoveCartIemTapped0
onRemoveCartIemTapped3
onRemoveCartIemTapped1
onRemoveCartIemTapped4
mfaani
  • 33,269
  • 19
  • 164
  • 293
Mohamed ALOUANE
  • 5,349
  • 6
  • 29
  • 60
  • Do you happen to have a sample project for this? I'd like to help you out on this. This should be pretty easy but I usually use the normal implementation of delegates and datasource methods of tableView in my ViewModel without using RxSwift's extensions (but using RxSwift in the entire project, not just in tableViews). – Glenn Posadas Jan 02 '19 at 14:19
  • 1
    Are you disposing `cellDisposeBag` in the cell's `prepareForReuse` method? If the cells are being reused without the subscriptions being disposed then it could cause this kind of behaviour. – Paul Jan 02 '19 at 15:20
  • no i don't use prepareForReuse at all. how can i do that even though i have cell dispose when button tapped – Mohamed ALOUANE Jan 02 '19 at 15:25
  • 1
    @Paul I fixed it, thank you :). post your comment as an answer. – Mohamed ALOUANE Jan 02 '19 at 16:45

1 Answers1

5

This is caused by the UITableView reusing the cell. To avoid having multiple subscriptions, you can override the cell's prepareForReuse() method and ensure any existing subscriptions are disposed.

I usually declare the DisposeBag as a var and then assign a new DisposeBag to it in prepareForReuse(). When the DisposeBag is deinited it will dispose all of the subscriptions it contains. Something like:

override func prepareForReuse() {
    super.prepareForReuse()

    cellDisposeBag = DisposeBag()
}
mfaani
  • 33,269
  • 19
  • 164
  • 293
Paul
  • 1,897
  • 1
  • 14
  • 28