RxSwift

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

概要

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

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

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

開発環境について

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

storyboardの配置

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

ここから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の表示とタップして画面遷移したりすることができるようになりましたね。

ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。