UITableViewのデリゲートからサブのビューを呼んでデータも渡す

# 要旨

* ビューコントローラー間のデータの受け渡しは、ストーリーボードを分けてinstantiateInitialViewControllerを使うと簡単
* .storyboardを新規作成したら is Initial View Controllerの設定を忘れない！

# 内容
　UITableViewにタッチすると、その情報を次のビューに送るサンプルです。
　こちらのツイートを見たので書きました。

<blockquote class="twitter-tweet" lang="ja"><p>やっとの思いでセクション分けしたUITableViewを作ることに成功したものの、選択された項目によって次のページに遷移させViewを分岐させる（選択された値を渡す）過程でエラー出まくりで詰んでる。。誰か、誰か、、 <a href="https://twitter.com/hashtag/Swift?src=hash">#Swift</a> <a href="http://t.co/y979LBMdVi">pic.twitter.com/y979LBMdVi</a></p>&mdash; かっぴー (@imachan0322) <a href="https://twitter.com/imachan0322/status/549781465563549696">2014, 12月 30</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

　たぶん、こういうモノだと思います (違ったらごめんなさい)。

　![名称未設定.png](https://qiita-image-store.s3.amazonaws.com/0/17957/74ebc54b-a254-9271-1c8c-e9a447b1b33c.png)

　もし違ったとしても、これは前にすごいハマってひどい目にあったので、備忘録も兼ねて書きます。更にやろうと思えば色々できますので、その雛形までに。
　[GitHubに置いておきます](https://github.com/tottokotkd/UITableViewSample/tree/master/testApp)。

※ 私の最近の趣味は「swift」でツイート検索してニヨニヨすることです。

## 細かい話
### ストーリーボードを分けると楽
　データを渡す方法はいろいろあるのでしょうが、テーブルビューから次のビューを呼ぶなら「専用コントローラー＆専用ストーリーボード」を用意するのが分かりやすくて楽だと思います (今回は関係ありませんが、セル専用xibを作ったりするのも楽ですね。どうもプログラムを書いてUIを作るのは苦手です)。
　まず最初にサブのビューコントローラーを用意して、データを渡すために変数を準備します。

```swift
class SubViewController: UIViewController {
    var targetText: String!
    @IBOutlet weak var label: UILabel! {
        didSet {
            label.text = targetText
        }
    }
}
```

　ちなみにdidSetの部分はこれを見て爆速でパクりました。

<blockquote class="twitter-tweet" lang="ja"><p>IBOutletに対してのdidSetかー！思いつかなかった / “まだObjective-Cで消耗してるの？ - horimislime blog” <a href="http://t.co/iPHAYDRulk">http://t.co/iPHAYDRulk</a></p>&mdash; sugitani (@sugitani) <a href="https://twitter.com/sugitani/status/542319417883783169">2014, 12月 9</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

　これは本当に便利です。viewDidLoadを占拠する連中をほぼ追放できます。

　ストーリーボードの設定は特に難しくないと思いますが、"is Initial View Controller" だけは本当に忘れがちなので注意したいところです。これを忘れると辛い目に遭います。
　そうして専用コントローラーを専用ストーリーボードにセットしたなら、いよいよ呼ぶ側の処理をデリゲートにて設定します。

```swift
extension ViewController {
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        // 渡すデータ
        let text = "\(contents[indexPath.section].title) \(contents[indexPath.section].items[indexPath.row])"
        // 次のビューコントローラーを用意
        let sb = UIStoryboard(name: "Sub", bundle: NSBundle.mainBundle())
        let vc = sb.instantiateInitialViewController() as SubViewController
        vc.targetText = text
        // プッシュ：この時点でIBOutletが用意され、didSetも働く
        navigationController?.pushViewController(vc, animated: true)
    }
}
```

### テーブルの中身をクラスにすると楽
「UITableViewの正しい使い方」というのが存在するのか知りませんし、おそらく人それぞれだと思いますが、最近の我が家では「データソース機能を事実上もっているクラス」を作るのがブームです。
(何となくこれが一番落ち着くというか… 根拠のない気分的なものです。)

　サンプルに入っているTableContentクラスのインスタンスは、セクション単位で情報を保持します。具体的には、セクションタイトルとセクション内部の文字群を持ちます。もちろんもっと大量の情報を持たせることもできますが、そういう時は `var items: [HogeClass]!` とでも書き換えて使うことになるかと思います。そっちの方が楽そうだからです。
　TableContentクラスには、プロパティリストから情報を持ってくるクラス関数と、セルを作って返すメソッドがあります。

```swift
class TableContent {
    var title: String!
    var items: [String]!
    
    class func readPropertyList() -> [TableContent] {
        var contents = [TableContent]()
        
        let filePath = NSBundle.mainBundle().pathForResource("tableContents", ofType: "plist")!
        let rawDic = NSDictionary(contentsOfFile: filePath) as [String: [String]]
        
        for title in rawDic["title"]! {
            let c = TableContent()
            c.title = title
            c.items = rawDic[title]
            contents.append(c)
        }
        return contents
    }
    func makeTableCell(tableview: UITableView, _ indexPath: NSIndexPath) -> UITableViewCell {
        let cellID = "tableViewCell"
        let cell = tableview.dequeueReusableCellWithIdentifier(cellID) as? UITableViewCell ?? UITableViewCell()
        cell.textLabel?.text = items[indexPath.row]
        return cell
    }
}
```

　.plistを使っているのでローカライズもできます。

　ここまで書いておけば、テーブルビューの実装はかなり簡単です。
　まずdidLoadの段階でプロパティリストを読んでおきます。

```swift
class ViewController: UITableViewController {
    // テーブルのコンテンツ
    var contents: [TableContent]!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // コンテンツの取得
        contents = TableContent.readPropertyList()
    }
}
```

　データソースの設定が必要ですが、これは機械的に書くだけですね。
　ビューコントローラーにはなるべく細かいことを書きたくありませんが、しかしデータソースを別クラスに分離する程でもないので、こういう構造にしてみました。

```swift
extension ViewController {
    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return contents.count
    }
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return contents[section].items.count
    }
    override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return contents[section].title
    }
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        return contents[indexPath.section].makeTableCell(tableView, indexPath)
    }
}
```

　なお言うまでもありませんが、この方法が最高で他はダメという趣旨ではありません。

### ViewControllerをエクステンションで細切れにすると楽
　今回のように短いサンプルだと読みにくいだけですが、1つのクラスでデリゲートの継承を5つも6つもやるときには別ファイルに分けたほうが楽だと思います。
　これも何方かの方法をパクりました (思い出せず)。