Search code examples
iosswiftuitableviewrx-swiftrx-cocoa

RxSwift - Textfield-Variable binding in tableview


I'm new to RxSwift and I have this code to setup a tableview which contains a textfield:

budget.expenses.asObservable()
  .bindTo(tableView.rx.items(cellIdentifier: ExpenseInputCell.cellIdentifier, cellType: ExpenseInputCell.self)){(row, element, cell) in

  cell.name.text = element.name.value
  cell.name.rx.text
    .bindTo(element.name)
    .addDisposableTo(self.disposeBag)
}
.addDisposableTo(disposeBag)

tableView.rx.itemDeleted
  .subscribe(onNext: {indexPath in
    self.budget.expenses.value.remove(at: indexPath.row)
  })
  .addDisposableTo(disposeBag)

Everything works fine until a row is deleted, because then the binding of the textfield to the correct object in the array is mixed up. For example lets say I have 7 items in the tableview and I delete the 5th row, the new 5th and 6th row both have the same value


Solution

  • The problem lies in the lifecycle of the subscription to element.name. Because it is tied to self.disposeBag, it will not be dismissed when the cell is reused, but when self is.

    You probably want to expose a new dispose bag on ExpenseInputCell and renew it in cell's prepareForReuse method.

    class ExpenseInputCell: UITableViewCell {
      // ..
    
      var disposeBag = DisposeBag()
    
      override func prepareForReuse() {
        self.diposeBag = DisposeBag()
      }
    }
    

    and in view controller

    budget.expenses.asObservable()
      .bindTo(tableView.rx.items(cellIdentifier: ExpenseInputCell.cellIdentifier, cellType: ExpenseInputCell.self)){(row, element, cell) in
    
      cell.name.text = element.name.value
      cell.name.rx.text
        .bindTo(element.name)
        .addDisposableTo(cell.disposeBag)
    }
    .addDisposableTo(disposeBag)