LoginSignup
2
4

More than 5 years have passed since last update.

[Swift]ReactiveKit/BondのObservable2DArrayの例

Last updated at Posted at 2016-09-28

まだ情報が少なく公式のドキュメントを読んでもわかりずらかったので共有しておく。

# 環境
swift 3.0
Xcode version 8.0
SwiftBond/Bond ~> 5.0

Observable2DArrayとは

Bondを利用していてUITableViewなどのデータを複数のセクションに分けたい場合に使用するデータモデル。
一つのテーブルにセクションが一つしかない場合は無理して使う必要はなくObservableArrayでも十分。

使い方

データサイド

まずセクションごとのデータを

let cities = Observable2DArraySection<SectionMetadata, String>(
  metadata: (header: "Cities", footer: "That's it"),
  items: ["Paris", "Berlin"]
)

のように定義する。metadataは

typealias SectionMetadata = (header: String, footer: String)

のように定義しておく。headerのタイトルだけしか必要なければStringで

let cities = Observable2DArraySection<String, String>(
  metadata: "Cities",
  items: ["Paris", "Berlin"]
)

でも良い。そしてObservable2DArraySectionの集合が

let array = MutableObservable2DArray([cities])

となる。

データを追加したい場合は

array.appendItem("Copenhagen", toSection: 0)

などのObservable2DArraySectionクラスのメソッドを利用する。

UIサイド

struct MyBond: TableViewBond {

  func cellForRow(at indexPath: IndexPath, tableView: UITableView, dataSource: Observable2DArray<SectionMetadata, String>) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = array[indexPath]
    return cell
  }

  func titleForHeader(in section: Int, dataSource: Observable2DArray<SectionMetadata, String>) -> String? {
    return dataSource[section].metadata.header
  }

  func titleForFooter(in section: Int, dataSource: Observable2DArray<SectionMetadata, String>) -> String? {
    return dataSource[section].metadata.footer
  }
}

なんとなく見覚えのあるメソッドだが、これをTableViewControllerとは別に(ここではMyBondとして)定義しておく。
この結果TableViewのクラスではviewDidLoadあたりで、

array.bind(to: tableView, using: MyBond())

を呼ぶだけで

var numberOfSections: Int
func numberOfRows(inSection: Int)
func cellForRow(at indexPath: IndexPath) -> UITableViewCell?

などのUITableViewのdelegateを定義しなくても済む。
さらにここでは説明しないがSignalを利用することにより、

tableView.selectedRow.observeNext { row in
  print("Tapped row at index \(row).")
}.disposeIn(bnd_bag)

などと書けるようになる。

はまったところ

itemにカスタムモデルを使う場合

上記だと単純に["Paris", "Berlin"]となっているところを

struct City {
    let name: String
}

のようなモデルの配列にしたい場合。

    let array = MutableObservable2DArray(
        [
            Observable2DArraySection<SectionMetadata, City>(
                metadata: (header: "Cities", footer: "That's it"),
                items: [
                    City(name: "Paris"),
                    City(name: "Berlin"),
                ]
            )
        ]
    )

とした上で、MyBondないのObservable2DArray<SectionMetadata, String>をObservable2DArray<SectionMetadata, City>としてやればよさそうだが、それだとtitleForHeaderやtitleForFooterでエラーになる。
解決方法は

class MyBond: TableViewBond {
    typealias DataSource = Observable2DArray<SectionMetadata, City>

    // 略
}

とDataSourceという名前に紐付る必要があった。

MutableObservable2DArrayをクラス間でどうやって共有するか

struct ViewModel {
    let array = MutableObservable2DArray(
        [
            Observable2DArraySection<SectionMetadata, City>(
                metadata: (header: "Cities", footer: "That's it"),
                items: [
                    City(name: "Paris"),
                    City(name: "Berlin"),
                ]
            )
        ]
    )
}

としてUI側からは

class TableViewController: UITableViewController {

    let viewModel = ViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel.array
            .bind(to: tableView, using: MyBond())
            .disposeIn(bnd_bag)
    }
}

class MyBond: TableViewBond {

    typealias DataSource = Observable2DArray<SectionMetadata, City>

    let viewModel = ViewModel()

    func cellForRow(at indexPath: IndexPath, tableView: UITableView, dataSource: DataSource) -> UITableViewCell {
        let city = viewModel.array[indexPath]

        // 略
    }
}

とすることでMutableObservable2DArrayの内容をTableに反映させることができた、ただ、動的にデータを追加したりすると途端にクラッシュしてしまう。
気づいてみれば当然だけど、この場合ViewModelをシングルトン化してあげなければいけない。

実装例
https://gist.github.com/ofl/dd005c1568681ff09423900354f075e8

使ってみて

Bondを1年近く使っているのだが、ReactiveKitとの統合のためか書き方が何度目かの大掛かりな変更となっている(のでこれから使い始める人は情報が少ないので大変)。
ただObservable2DArraySectionについては以前のMutableArrayを多段にする書き方よりは好ましくなったと思う。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4