【Swift】RxSwift勉強してみたPart10

#はじめに
[前回](https://qiita.com/REON/items/08a19b644e2aac75eb83)
今回は、UITableViewとRxSwiftをバインドしてみたいと思います。

#カスタムセルを使わない場合
![ScreenShot 2021-05-18 1.41.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/dab95942-e020-1560-8a4e-d1d5c8fb8f5e.png)

ここでバインドしていますね。`element`に`Item`の情報が入ってきます

```swift
items.bind(to: tableView.rx.items(cellIdentifier: "cell")) { row, element, cell in
    cell.textLabel?.text = element.name
    cell.backgroundColor = element.color
}
```

#カスタムセルを使う場合
カスタムセルを使う場合は、カスタムセルをテーブルビューに登録し、bindの中を以下のように変更します。
`cellType`で作成したカスタムセルを指定しています。

```swift
items.bind(to: tableView.rx.items(cellIdentifier: CustomTableViewCell.identifier,
                                  cellType: CustomTableViewCell.self)) { row, element, cell in
    cell.configure(item: element)
}
.disposed(by: disposeBag)
```

セルは以下のようにしました。

```swift
final class CustomTableViewCell: UITableViewCell {
    @IBOutlet private weak var nameLabel: UILabel!
    
    static var identifier: String { String(describing: self) }
    static var nib: UINib { UINib(nibName: String(describing: self), bundle: nil) }
    
    func configure(item: Item) {
        nameLabel.text = item.name
        backgroundColor = item.color
    }
}
```

#複数のカスタムセルをIDによって分けたい場合
セルをクロージャの中で生成します。
`isEnded`は例として、書きました。終わっている時と終わっていない時で表示させるセルを分ける（IDによって）場合を想定しています。

```swift
items.bind(to: tableView.rx.items) { tableView, row, element in
    if isEnded {
        let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier) as! CustomTableViewCell
        cell.configure(item: element)
        return cell
    } else {
        let cell2 = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell2.identifier) as! CustomTableViewCell2
        cell2.configure(item: element)
        return cell2
    }
}
.disposed(by: disposeBag)
```


#自作DataSourceを使う場合
こちらは少しだけ、難易度が上がります。

テーブルビューの`didSelectedRowAt`などを実装したいってなった時に使います。

```swift
let dataSource = MyDataSource()
items.bind(to: tableView.rx.items(dataSource: dataSource))
    .disposed(by: disposeBag)
```

```swift
final class MyDataSource: NSObject, UITableViewDataSource, RxTableViewDataSourceType {
    typealias Element = [Item]
    var items = [Item]()
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.identifier,
                                                 for: indexPath) as! CustomTableViewCell
        let item = items[indexPath.row]
        cell.configure(item: item)
        return cell
    }
    
    func tableView(_ tableView: UITableView, observedEvent: Event<[Item]>) {
        Binder(self) { dataSource, element in
            guard let items = element.element else { return }
            dataSource.items = items
            tableView.reloadData()
        }
        .onNext(observedEvent)
    }
}
```

データソースクラスを作り、`NSObject`, `UITableViewDataSource`, `RxTableViewDataSourceType`の三つに準拠させる。
`RxTableViewDataSourceType`は`tableView(_ tableView: UITableView, observedEvent: Event<[Item]>)`を使うための、プロトコルです。
![ScreenShot 2021-05-18 7.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/954451/8f452015-9e1b-a0a1-cd21-22d2ad41b736.png)
これを準拠させることにより、`tableView(_ tableView: UITableView, observedEvent: Event<[Item]>)`には、データがオブザーバーにやってきたときの処理を記述します。
今回の例では、`items`を更新して`tableView`をリロードし、描画する処理を記述しています。
そして、`onNext()`でイベントを流します。
DataSourceを自作する場合の全体のコードを上げておきます[GitHub](https://github.com/0429oonishi/TableViewRxSwift-practice)


#おわりに
[参考記事](https://qiita.com/hironytic/items/71bc729abe73ab9f0879)