読者です 読者をやめる 読者になる 読者になる

Pragmatic ball boy

iOSを中心にやってる万年球拾いの老害エンジニアメモ

RxSwiftでTableView その1

iOS MVVM RxSwift Swift

RxSwiftでTableViewとdatasourceをbindingさせる方法はいくつかあるようなので1つずつ見ていきます。 今回はrx_itemsWithCellIdentifilerを使ってみます。

rx_itemsWithCellIdentifier

単にSectionが1つのリストをTableViewに表示するだけであればrx_itemsWithCellIdentifierを使えば非常にシンプルに実装できます。

ViewController

class ListViewController: UIViewController {

  @IBOutlet weak var tableView: UITableView!
  @IBOutlet weak var button: UIButton!

  private let viewModel = ListViewModel()
  private let disposeBag = DisposeBag()

  override func viewDidLoad() {
    viewModel.friends.asObservable()
      .bindTo(tableView.rx_itemsWithCellIdentifier("Cell")) { (row, element, cell) in
        cell.textLabel!.text = element
      }
      .addDisposableTo(disposeBag)

    tableView.rx_itemSelected
      .subscribeNext { [weak self] indexPath in
        self?.viewModel.selectAtIndex(indexPath.row)
        self?.tableView.deselectRowAtIndexPath(indexPath, animated: true)
    }
    .addDisposableTo(disposeBag)

    button.rx_tap
      .bindNext {
        self.viewModel.add()
      }
      .addDisposableTo(disposeBag)
  }
}

ViewModel

final class ListViewModel {
  let friends = Variable<[String]>([])

  init () {
    friends.value.append("1")
    friends.value.append("2")
    friends.value.append("3")
  }

  func selectAtIndex(index: Int) {
    print(friends.value[index])
  }

  func add() {
    friends.value.append("10")
  }
}

このように、単に表示するだけであればrx_itemsWithCellIdentifierとdatasouceをbindingするだけなのですごく楽です。

ただRxSwift内部のソースを見てみると、以下のようにdatasourceに変化があった場合reloadData()を使っているので全体に再描画が発生します。

/// RxTableViewReactiveArrayDataSource
class RxTableViewReactiveArrayDataSource<Element>
    : _RxTableViewReactiveArrayDataSource
    , SectionedViewDataSourceType {
    typealias CellFactory = (UITableView, Int, Element) -> UITableViewCell
    
    ...
    
    func tableView(tableView: UITableView, observedElements: [Element]) {
        self.itemModels = observedElements
        
        tableView.reloadData()
    }
}

rx_itemsWithCellIdentifierの使い所

以上のことから使い所を考えると

  • Sectionが1つしかない
  • datasourceに変化があったときに毎回reloadData()が走っても問題ないような場合
  • cellの挿入にアニメーションが不要

といった感じかなと