RxSwiftでUITableViewのセルをタップした時にバインディングされているitemのmodelの情報を取得する

概要

今回はRxSwiftを使ってUITableViewで表示されたセルのitemをタップした時にitemのmodelの情報を取得する方法について解説します。
前回の

blog.tamappe.com

と似てるようで実は違ったりします。

この方法によりリスト表示のセルをタップして画面遷移させたい時に値を渡す実装が可能になります。

開発環境について

Xcode: 10.1
Swift: 4.2
RxSwift: 4.4.0
RxCocoa: 4.4.0

storyboardの配置

前回の記事のstoryboardを拝借しますのでその続きになります。

blog.tamappe.com

ここからstoryboardを編集していきます。

今回は画面遷移ように詳細画面を追加するのでDetail.storyboardのstoryboardのファイルを追加して新しいViewControllerを配置させます。

f:id:qed805:20190219225051p:plain
detail_storyboard

この新しいViewControllerのクラスをDetailViewControllerとします。

DetailViewController.swift

import UIKit

class DetailViewController: UIViewController {
    
    var nameString: String?

    override func viewDidLoad() {
        super.viewDidLoad()

        self.title = nameString
    }
}

となります。

そして、プッシュ遷移にしたいので最初の画面のリスト一覧画面にはNavigationViewControllerを配置させます。

f:id:qed805:20190219225327p:plain
main_storyboard

このようになります。
storyboard など新しいファイルの追加に関してはグーグル先生に任せたいので省略します。
storyboardの配置の解説は以上になります。

ソースコードの編集

やっとここからViewController.swiftソースコードに追加のコードを書きます。

ViewController.swift

import UIKit
import RxCocoa
import RxSwift

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!

    let data = Observable<[CustomCellModel]>.just([
        CustomCellModel(name: "山田花子", email: "hanako@gmail.com"),
        CustomCellModel(name: "田中太郎", email: "taro@gmail.com"),
        CustomCellModel(name: "石田真一", email: "shinichi@gmail.com")
        ])
    
    var disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // CustomCellのNibファイルの登録
        tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "CustomTableViewCell")
        
        data.bind(to: tableView.rx.items(cellIdentifier: "CustomTableViewCell", cellType: CustomTableViewCell.self)) { row, element, cell in
                // row: Int アイテムのインデックス
                // element: Item(CustomCellModel) アイテムのインスタンス
                // cell: CustomCell セルのインスタンス
                
                // ここでセルの中身を設定する
                cell.nameLabel.text = element.name
                cell.emailLabel.text = element.email
            }
            .disposed(by: disposeBag)
        
        // tableViewのセルをタップした時にcellにバインディングされているデータを取得してハンドリング
        tableView.rx.modelSelected(CustomCellModel.self)
            .subscribe(onNext: { [weak self] model in // model = CustomCellModel
                let storyboard = UIStoryboard(name: "Detail", bundle: nil)
                let detailVC = storyboard.instantiateInitialViewController() as! DetailViewController
                detailVC.nameString = model.name
                self?.navigationController?.pushViewController(detailVC, animated: true)
            })
            .disposed(by: disposeBag)
    }
}

tableView.rx.modelSelected(CustomCellModel.self)modelSelectedがタップした時のセルのitemのモデル情報を取得する関数になります。
これをsubscribeして得られる引数のmodelの中にindexPathに応じたCustomCellModelが格納されています。
RxSwiftを使わない処理ならarray[indexPath.row]としてmodel情報を取得する作業が必要でしたらRxSwiftでは必要なくなります。
(その代わりそれを知っていない場合はハマる原因に繋がります。)

まとめ

UITableViewDelegateでdidSelectRowAtするときに書くような処理の部分のハンドリング方法が分かりました。
これでUITableViewの表示とタップして画面遷移したりすることができるようになりましたね。