RxSwift学びの過程〜tableViewCellの操作編〜


背景

既存コードをRxSwiftにて書き直していたとき、cellの操作で詰まりましたので備忘録的にアウトプット。
やはりこいつはすごくクセが強い。

cell上に配置したUIButtonの操作

Issue 1 : cell番号を取得したかった

MVVMで開発をしていてcellCustomCellとして作成していたとき、UIButtonをセル上に配置していたのでボタンタップの検知をCustomCellViewに記載していました。
ちなみにUIButtonのタップ検知は

  • UIButton.rx.tap

となります。

ここで、UIButtonをタップした時にそのcellのindex(tag)を取得したかったのですが、どのセルのボタンをタップしても0しか取得できませんでした。

func favButtonSetup() {
    favButton.rx.tap.asDriver().drive(onNext: { [weak self] _ in

        let row = self!.tag
        print(row) // 選択されたセルのインデックス(tag)を取得したかったが、いつも0

    }).disposed(by: disposeBag)
}

RxSwiftを使わないプレーンな書き方だと@IBOutlet buttonTapped(_:)にてself.tagで任意のセルに乗っかっているボタンのイベントを取得できるんですよね。

Issue2 : お気に入りボタンのon/off切り替えが上手くいかない

お気に入りボタンのon/off、データの整合などで操作対象のcellを取得したいときにもtagで操作対象の番号を取得するやり方は使えます。

セルの位置に応じてお気に入りボタンをon/off処理(画像を切り替える)ものも実装していましたが、取得できる番号が0のみなのでどのボタンを押しても切り替わるのは一番上のセルだけでした。

コードは大したことないのを上に追加するだけなので割愛します。

原因・解決法

まず調べた中での解決法として、

  • tap.asDriver()ViewControllerにあるセルをどうこうする場所で呼ぶ。(cellForRowAtとかRxTableViewSectionedReloadDataSourceとか人によって違うと思います)
  • override func prepareForReuse()にてDisposeBag()を毎度作成し、これでDisposeする
// ViewController内
dataSource = RxTableViewSectionedReloadDataSource<SectionModel>(configureCell: {(_, tableView, indexPath, item) in
    let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! ListCell

    cell.configure(item: item)

    cell.favButton.rx.tap.asDriver().drive(onNext: { [weak self] _ in

        //TableViewCell内での記述ではないので indexPath にて rowを取得
        let row = indexPath.row

    //cell側で作成したdisposeBag()を呼ぶ
    }).disposed(by: cell.disposeBag)

    return cell
})



// CustomCellView内
var disposeBag = DisposeBag()

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

これにはTableViewCellというオブジェクトを作成するライフサイクルに元付いた問題があり、毎度セルを作成する際に作るDisposeBag()Disposeする必要があるようです。

終わりに

問題は解決されました。
が、設計上CellViewにある操作はCustomCellViewで行った方がいいんだろうなぁと思うので、このようにViewControllerにcellの操作を書くのはナンセンス?と思います。

CellView内でUIButton時にcellの番号が取得できたりする方法があれば教えていただければ嬉しいです。

参考URL
How to use rx_tap on UIButton of UITableViewCell · Issue #288 · ReactiveX/RxSwift · GitHub
what is best way i can handle button tap in UITableViewCell using RX. · Issue #119 · RxSwiftCommunity/RxDataSources · GitHub
RxSwift UITableViewCell上に配置したボタンの動作 - Qiita