Search code examples
uitableviewrx-swiftuidatepicker

BehaviorRelay in tableviewcell


I'm a beginner to RxSwift so I'll try to explain my scenario... I'm using a UITableView together with RxTableViewSectionedReloadDataSource.

In one of my cells which displays a UITextField I have this:

var observer: BehaviorRelay<String?>! {
    didSet {
        observerDisposable = textField.rx.text.bind(to: observer)
    }
}

Now whenever that cell is selected I display a popup view (not in the cell) where the user can select a date from a UIDatePicker which has a BehaviorRelay<Date?>. So what I want to do is that when the user selects a date I want to update that textfield cell with the selected date.

How would I do this with RxSwift?


Solution

  • First things first, Observables, Subjects and Relays should never be in a var, they should always be lets.

    Now to solve your problem... I would expect to see code that is something like this:

    let dateText = PublishSubject<String>()
    
    let date = tableView.rx.itemSelected
        .filter(isDateTableView)
        .flatMapFirst { [unowned self] (_) -> Driver<Date> in self.getDate() }
    
    date
        .map { dateFormatter.string(from: $0) }
        .bind(to: dateText)
        .disposed(by: disposeBag)
    
    let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String, Int>>(configureCell: { dataSource, tableView, indexPath, item in
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ExampleTableViewCell
        if isDateTableView(indexPath) {
            dateText
                .bind(to: cell.textField.rx.text)
                .disposed(by: cell.disposeBag)
        }
        return cell
    })
    
    Driver.just([SectionModel<String, Int>(model: "test", items: [12])])
        .drive(tableView.rx.items(dataSource: dataSource))
        .disposed(by: disposeBag)
    

    All of the above code (including the definition of dateText) would go into your viewDidLoad or a function that viewDidLoad calls.