1

I have some odd problem with UITableViewCell when I use MVVM pattern with RxSwift. I can't describe it, but I will try to explain.

Let's say we have simple UITableViewCell

class MyTableViewCell: UITableViewCell {
  var disposeBag = DisposeBag()

  override func prepareForReuse() {
    super.prepareForReuse()
    disposeBag = DisposeBag()
  }

func bind(to viewModel: MyCellViewModel) {
    viewModel.randomValue.asDriver()
      .drive(onNext: { [weak self] value in
        guard let self = self else { return}
        print(value) // WHEN TWO CELLS I GET NEW VALUES JUST IN ONE OF THEM
      })
      .disposed(by: disposeBag)
    
}

with ViewModel with simple timer.

class MyCellViewModel: NSObject {
  let randomValue = PublishSubject<Int>()
  init() {

 Observable<Int>.timer(.seconds(1), period: .seconds(1), scheduler: SerialDispatchQueueScheduler(qos: .userInteractive))
        .map { _ in Int.random()}
        .do(onNext: {
          print($0) // WORK PERFECT FOR BOTH
        })
        .bind(to: randomValue)
        .disposed(by: rx.disposeBag)
 }

}

I also use RxDataSources to fill my tableView.

   private func makeDataSource() -> RxTableViewSectionedAnimatedDataSource<Section> {
        RxTableViewSectionedAnimatedDataSource<Section>(configureCell: { _, tableView, indexPath, item in
          switch item {
          case let .myItem(cellViewModel):
            let cell = tableView.dequeueReusableCell(with: MyTableViewCell.self, for: indexPath)
            cell.bind(to: cellViewModel)
            return cell
          }
        })
      }

The problem is that when I have two cells, I get new values in one of them and not in the other.

Pay attention to the method bind(to viewModel

But everything is ok when I change RxTableViewSectionedAnimatedDataSource to RxTableViewSectionedReloadDataSource.

How to make it work with RxTableViewSectionedAnimatedDataSource? I understand the difference between them, but in this case I don't know how does that affect it?

I also checked memory graph and saw just two instances of cells and two instances of cellViewModels. So I hope there are no leaks.

Thanks for any help!

  • It would help if you posted code that compiles... – Daniel T. Mar 15 '22 at 17:41
  • You are going to have to post a more complete example. I adjusted your code so it will compile and it works fine. Both cells produce output. – Daniel T. Mar 15 '22 at 18:29
  • @DanielT. I have creates a test project to show the issue https://github.com/rezuantpr/RxCellError-Test – Michel Rivera Mar 16 '22 at 22:15
  • @DanielT. Could you check it please? I suppose problem is next: firstly the tableView has one cell with id = 1, then I reload it with id = 1,2. So the CellViewModel (1) is released, but the cell does not bind to a new CellViewModel, because dataSource thinks that there are no changes. And Cell(1) does not produce output. – Michel Rivera Mar 16 '22 at 22:25

1 Answers1

1

You implemented your ItemMode.== incorrectly. It doesn't actually check for equality, it only checks the identity. Remove the function and let the compiler generate the correct one for you.

Daniel T.
  • 32,821
  • 6
  • 50
  • 72