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の挿入にアニメーションが不要
といった感じかなと