Help us understand the problem. What is going on with this article?

UITableView の Section を Swift の enum を使って安全に記述する方法

More than 3 years have passed since last update.

環境

  • 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 が表示されます。

image

このコードで重要なのは以下の2箇所ぐらいです。

大事な所1
enum Section: Int {
    case Animals = 0
    case Foods
}
大事な所2
    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 の種類が増えた場合、例えば :beer: が追加してみます。

🍺追加
enum Section: Int {
    case Animals = 0
    case Foods
    case 🍺
}

すると以下の様な感じでエラーが出ます。

switch must be exhaustive... -> switch は網羅的でなければなりません...

といった具合にコンパイル時に switch の case に漏れがあるということをえ教えてくれています。

もちろんエラーが発生しているのでこのプログラムは実行できません。

間違ったプログラムが実行できないので 安全 なのです。

image

余談ですが、 Objective-C で enum を作ってキャストしてから switch case すると似たようなことは出来ますが、未定義な case の値(swift の場合は None になるパターン)があった場合、コンパイル時に検出はできず実行時にクラッシュしますので若干安全ではないです。

悩み

セルを返す delegate (func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell )では戻り値が UITableViewCell? ではなく UITableViewCell なので未定義な section が渡された場合どのように処理すると綺麗なのかが悩ましい(場合によるだろうけど..)

今回の場合は面倒だから基本的にクラッシュするようにしてる。

まとめ

Swift では UITableView の Section を enum で定義することでわりと安全にプログラムすることができる。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away