環境
- Xcode 7.3
- Swift 2.2
- そんなに新しい機能は使ってないので特に気にしないでください
背景
UITableView の Section は Int なので switch case で網羅性をチェックできないので仕様変更に変更に弱いのが悩みの種です。
例えば以下のコードだと section == 0
ってどんな Section だっけ? ってなったり、 default を使っているので仕様変更で section == 2
が追加された時に記述漏れが発生したりします。
人間がこの辺を把握するのは辛いので可能であればコンパイル時に Section の追加漏れがあるよ!ってことを警告(もしくはエラー)して欲しいです。
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch section {
case 0:
return 3
case 1:
return 4
default:
return 0
}
}
そこで Swift の enum の出番
PlayGround のコードを Gist に貼り付けておきました。
動かしてみたい人は以下のコマンドを実行してダウンロードできますので試してみてください。
curl https://gist.githubusercontent.com/mironal/d640c57e06ce2f644137e8dc182e1256/raw/622a731be4e695fe2c7194eb579e7e600e3a3fe9/UITavlewViewSection.swift > UITablewViewSection.playground
動かすとこんな感じの UITableView が表示されます。
このコードで重要なのは以下の2箇所ぐらいです。
enum Section: Int {
case Animals = 0
case Foods
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
switch Section(rawValue: section) {
case .Some(.Animals):
return animals.count
case .Some(.Foods):
return foods.count
case .None:
return 0
}
}
大事な所1
大事な所1で Int の enum を定義して、それぞれのセクションに名前をつけています(今回は Animals と Fools)。
このようにすることでまず Int の section を enum の Section に変換できるのでより安全にプログラミングできるようになります。
何が安全なのかといいますと次の説明でわかります。
大事な所2
そして、大事な所2で UITableView の delegate に渡される Int の section を enum の Section に変換して switch case しています。
このように Int ではなく enum で switch することで enum の種類が増えた場合、例えば が追加してみます。
enum Section: Int {
case Animals = 0
case Foods
case 🍺
}
すると以下の様な感じでエラーが出ます。
switch must be exhaustive...
-> switch は網羅的でなければなりません...
といった具合にコンパイル時に switch の case に漏れがあるということをえ教えてくれています。
もちろんエラーが発生しているのでこのプログラムは実行できません。
間違ったプログラムが実行できないので 安全
なのです。
余談ですが、 Objective-C で enum を作ってキャストしてから switch case すると似たようなことは出来ますが、未定義な case の値(swift の場合は None になるパターン)があった場合、コンパイル時に検出はできず実行時にクラッシュしますので若干安全ではないです。
悩み
セルを返す delegate (func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
)では戻り値が UITableViewCell?
ではなく UITableViewCell
なので未定義な section が渡された場合どのように処理すると綺麗なのかが悩ましい(場合によるだろうけど..)
今回の場合は面倒だから基本的にクラッシュするようにしてる。
まとめ
Swift では UITableView の Section を enum で定義することでわりと安全にプログラムすることができる。