UITableViewとかUITableViewControllerの使い方メモ＋UITableViewCellのxibとかstoryboardのメモ

storyboard も使い慣れていなければ、xibでのUI作成もイマイチよくわかっていない。
何度か使用している UITableView だが、何度か調べてみても色々なやり方があって理解できていない。
これを機にちょっとまとめてみようと思ったのがこの記事のキッカケ。

- ViewContoroller
    - UIViewController を使う場合
    - UITableViewController を使う場合
- UITableViewCell
    - xib で UITableViewCell を作る場合
    - storyboard 上で UITableViewCell を貼り付ける場合

この辺が自分の中であまり理解できていない

# storyboard(UIViewController, UITableView) + xib(UITableViewCell)

(個人的によく利用しているやり方)

## 完成イメージ

### Projectディレクトリ の状態

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/a7810a2d-a492-549a-3900-dc95e4ae2501.png" width="256">

### storyboard の状態

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/9f0bdceb-8aac-47cc-73de-7a4820b348f1.png" width="256">

## `ViewController` の準備

1. `Storyboard` を開いて `UITableView` を `ViewController` に貼り付ける
1. `UITableView` を `ViewController.swift` に Outlet で紐付ける

## `UITableViewCell` の準備

1. TableViewCell.swift と TableViewCell.xib の作成
    1. `メニューバー` -> `File` -> `New...` -> `iOS - Source - Cocoa Touch Class` を選択
    1. `Subclass of:` で `UITableViewCell` を選択
    1. `Also create XIB file` にチェックを入れて作成
1. `XIB` を開いて適当に `UILabel` でも貼り付ける
1. `UILabel` を `TableViewCell.swift` に Outlet で紐付ける
1. `Identifier` を設定する

![20160807143025.png](https://qiita-image-store.s3.amazonaws.com/0/53393/b5cb7e04-cf16-97c5-8268-3e7f6382dfe2.png)

## `ViewController.swift` の実装

```swift:ViewController.swift
// UITableViewDataSource と UITableViewDelegate を実装
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // XIBファイルからUINibのインスタンスを生成
        let nib = UINib(nibName: "TableViewCell", bundle: nil)
        // UITableViewにXIBファイルを登録
        tableView.registerNib(nib, forCellReuseIdentifier: "Cell")
        tableView.delegate = self
        tableView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // MARK : UITableViewDataSource
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // とりあえず適当に10個のセルを用意
        return 10
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
        cell.label.text = "Cell No." + String(indexPath.row)
        return cell
    }
    
    // MARK : UITableViewDelegate
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = self.tableView(tableView, cellForRowAtIndexPath: indexPath) as! TableViewCell
        print(cell.label.text)
    }
}
```

# storyboard(UIViewController, UITableView + UITableViewCell)

(まとめる上で理解しようと思って試してみた)

## 完成イメージ

### Projectディレクトリ の状態

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/28975f0f-bdd0-bdb4-2329-9975ac25b5c9.png" width="256">

※ storyboard 上で UITableViewCell のUIを扱うので xib が不要になった

### storyboard の状態

<img src="https://qiita-image-store.s3.amazonaws.com/0/53393/06ef2309-e4fb-b7f3-dd48-dc011d070ad8.png" width="256">


## `ViewController` の準備

1. `Storyboard` を開いて `UITableView` を `ViewController` に貼り付ける
1. `UITableViewCell` を　`UITableView` に貼り付ける
1. `UITableView` を `ViewController.swift` に Outlet で紐付ける

## `UITableViewCell` の準備

1. `Identifier` を設定する

![20160807143025.png](https://qiita-image-store.s3.amazonaws.com/0/53393/b5cb7e04-cf16-97c5-8268-3e7f6382dfe2.png)

## `ViewController.swift` の実装

```swift:ViewController.swift
// UITableViewDataSource と UITableViewDelegate を実装
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        tableView.delegate = self
        tableView.dataSource = self
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    // MARK : UITableViewDataSource
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // とりあえず適当に10個のセルを用意
        return 10
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        cell.textLabel.text = "Cell No." + String(indexPath.row)
        return cell
    }
    
    // MARK : UITableViewDelegate
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let cell = self.tableView(tableView, cellForRowAtIndexPath: indexPath)
        print(cell.textLabel.text)
    }
}
```

## 気づいたこと

- UITableViewCellには　`textLabel` という UILabel がデフォルトで居た・・・
- `storyboard(UIViewController, UITableView) + xib(UITableViewCell)` のようにカスタムセルにしたい場合は `TableViewCell.xib` は不要になるが `TableViewCell.swift` は必要でとなって `storyboard` 上の UITableViewCell に紐付けてあげれば良いのか・・・

# UITableViewController で作成

(個人的にイマイチ理解していなかったやり方)

上記２つの方法の後に UITableViewController を storyboard 上に貼り付けて理解した
ただの `UIViewController` + `UITableView` + `UITableView` で２番目の構成と同じだった

ひとつ違うのは UITableViewController 専用のメソッドが切られていること

```swift:UIKit/UITableViewController
@available(iOS 2.0, *)
public class UITableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    public init(style: UITableViewStyle)
    public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?)
    public init?(coder aDecoder: NSCoder)
    
    public var tableView: UITableView!
    @available(iOS 3.2, *)
    public var clearsSelectionOnViewWillAppear: Bool // defaults to YES. If YES, any selection is cleared in viewWillAppear:
    
    @available(iOS 6.0, *)
    public var refreshControl: UIRefreshControl?
}
```

# まとめ

storyboard だったり xib だったり、自動で色々付いてる UITableViewController だったり、
なかなか取っ付き難い感はあるけど、Qiitaの場を借りてちゃんとまとめてみたら理解が進んだ。