.xibを用いたUITableViewCellの実装方法 (CustomCell) PART1

2019年、2月からiOSインターンとして[JX通信社](https://jxpress.net/)にお世話になっています。インターンとして入ったばっかなのでそこで行った実習としてUITableViewCellのxibを用いたカスタムセルの実装方法をここにまとめたいと思います。

**この記事はPARTが２つに分かれています。これはPART1です。PART2では2通りの方法でAPIを利用してTableViewを作成しています。よかったら下から確認してきてください。**
PART2: https://qiita.com/ostk0069/items/385acd1875c0d3e3277f

今回実装にあたって作成したものをGitHubに作成しておいたのでコードだけ見たい人はこちらからどうぞ。

とりあえずswift内のデータを表示させたもの*
https://github.com/takumaosada/customCellTutorial

*終了後、Alamofire, SwiftyJSONを用いてAPI通信を行い表示させたもの
https://github.com/takumaosada/customCellTutorial/tree/feature/swifty_json

*終了後、Alamofire, Decodable(codable)を利用してAPI通信を行い表示させたもの
https://github.com/takumaosada/customCellTutorial/tree/feature/decodable

# はじめに
xcodeを立ち上げ、projectを作成し、プロジェクト名を設定しましょう。
ここでは特に不都合がなければ`Create a New Xcode Project`を選択しましょう。
<img src="https://qiita-image-store.s3.amazonaws.com/0/176180/3d55879a-958a-3bf0-280b-4105a73e0df4.png" width=50%>

その後は`Single View App`を選択し、そのままproject名をつけましょう。
（名前はなんでも大丈夫です。）
![スクリーンショット 2019-02-17 17.23.57-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/1a3767f9-336a-8835-5ef6-447aff6a2543.png)

そうするとこのような画面が出てくると思います。
![スクリーンショット 2019-02-17 17.29.35-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/0ff1d4b7-1edf-fcc3-c409-7a3e177531e4.png)


# .xibを使用する・使用しないの選択にあたって
それでは、codingを始めていきたいのですが、`UITableView`を利用してCellを作成する場合、

 - 直接UIViewControllerに記述する
 - .xibを使用する
 
の２択が存在します。それぞれのメリット・デメリットは

- **直接UIViewControllerに記述する**
    - メリット: .xibを使用するよりもstoryBoardに直接UITableViewCellを乗っけることができるのでファイルの数が少なくて済む。
    - デメリット: UIViewControllorへ記述する量が増えてしまう

- **.xibを使用する**
    - メリット: UITableViewと UITableViewCellを分離して記述することができる。
    - デメリット: Cellへのあたいの継承とか少しだけめんどい

他にもあるかもしれませんが、どちらが絶対に正しいというものはないので適切な方を選択しましょう。今回はタイトル通り、.xibファイルを用いて作成します。

#.xibファイルの作成
写真通りにproject名のファイルにカーソルを合わせながら右クリックし、`New File...`を選択します。
![スクリーンショット 2019-02-17 17.46.24-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/da09f4a7-e9de-8b8f-2491-a7d66ad15c93.png)
`Cocoa Touch Class`を選択
![スクリーンショット 2019-02-17 17.46.32-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/b1f89a98-c17b-e1b0-cc1a-72ef33564278.png)

名前は適当に関連した言葉を添えて命名しましょう
**ここで大事なのは、`Also create XIB file`にチェックすることです。**
![スクリーンショット 2019-02-17 17.50.34-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/d48597e3-372f-c57c-30e7-9d0d95254859.png)
そしたら最後に2つのファイルが同時に作成されたことを確認することができます。
![スクリーンショット 2019-02-17 17.50.54-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/39d00174-a9b3-424b-cec9-cec1be1c9a91.png)

   

#UITableViewの作成
`Main.storyboard`を開き、右下のメニューから`UITableView`を選択してクリックします。
![スクリーンショット 2019-02-17 18.06.23-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/39f501ac-452b-e847-7b51-4f978adef2c0.png)
`UITableView`をクリックした結果が下なのですが、これだと一覧表示したいTableが小さすぎるので画面いっぱいに拡大します。
![スクリーンショット 2019-02-17 18.06.37-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/5d2dc859-e056-94eb-d168-f7e4e8b65137.png)
拡大した結果がこれです。
![スクリーンショット 2019-02-17 18.06.55-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/955e61ec-5328-bce5-08d6-6ae74df4d3cc.png)
次に`UITableView`と`UIViewController`の紐付けをしましょう。
![スクリーンショット 2019-02-17 18.22.06-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/4daaf7dd-e827-53c4-b565-511ce8be79cb.png)
下の写真のように

```swift:ViewController.swift
@IBOutlet weak var stationList: UITableView!
```
の横の部分に◉が存在するか確認してください。
![スクリーンショット 2019-02-17 18.22.25-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/d2bacd94-5064-0db9-93fa-8a09d8e5f5c5.png)

#データを入れるmodelを作成する
実際、UITableViewに簡単な情報を表示するだけではmodelの作成は必須ではないですが、のちにAPIを叩いて駅の情報を取得する必要があります。なので今回は作ることにします。

```swift:Station.swift
import Foundation

class Station : NSObject {
  var name: String
  var prefecture: String

  init(name: String, prefecture: String){
    self.name = name as String
    self.prefecture = prefecture as String
  }
}
```

#TableViewCellに記述する
完成したものは

```swift:StationTableViewCell.swift
import UIKit

class StationTableViewCell: UITableViewCell {

   @IBOutlet var name: UILabel!
   @IBOutlet var prefecture: UILabel!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }
  
  func setCell(station: Station) {
    self.name.text = station.name as String
    self.prefecture.text = station.prefecture as String
  }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
    
}
```

`setCell`というfunctionを定義しました。これによって上で定義したUILabelにUITableViewから受け取った値を入れることができます。


`StationTableViewCell.xib`と`StationTableViewCell.swift`を両方開いた状態で、先ほどのUITableViewを右下から持ってきたように次はUILabelを２つ選択します。これもまた同様の方法ですが、connectした際には◉が表示されていることを確認の上、次に進んでください。
![スクリーンショット 2019-02-17 19.05.06-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/a418e49a-6148-c78b-4c48-1ea9b3da4f5f.png)

`StationTableViewCell.xib`に一旦UILabelをおいたものの、これではスタイルが崩れてしまいます。
ここは各自自由に変えていただだいてかまいません。サンプルとしてのっけておきます。
![スクリーンショット 2019-02-17 19.23.15-min.png](https://qiita-image-store.s3.amazonaws.com/0/176180/9a1bc25f-4764-2558-79d0-670445bce67b.png)

これは作成したUILabelを選択したのち、表示されているmodalの矢印の先のアイコンをクリックすることでモダルが表示されます。とりあえず、４方に全て16pxの感覚を開けておきました。(これをもう一つのUILabelでも行いました)




#ViewControllerにUITableViewの記述を行う
今回の完成形はこちらです。

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

  @IBOutlet weak var stationList: UITableView!
  var stations:[Station] = [Station]()
  
  override func viewDidLoad() {
    super.viewDidLoad()
    StationList.dataSource = self
    StationList.delegate = self
    StationList.register(UINib(nibName: "StationTableViewCell", bundle: nil), forCellReuseIdentifier: "StationTableViewCell")
    self.setupStations()
  }

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
  
  func setupStations() {
    stations = [Station(name: "飯田橋", prefecture: "東京都新宿区"), Station(name: "九段下", prefecture: "東京都千代田区"), Station(name: "御茶ノ水", prefecture: "東京都文京区") ];
  }
  
  func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
  }
  
  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return stations.count
  }
  
  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "StationTableViewCell", for: indexPath ) as! StationTableViewCell
    
    cell.setCell(station: stations[indexPath.row])
    
    return cell
  }
}
```

書いたコードのついて解説していきます。UITableViewを今回使うので最初に

```swift:ViewController.swift
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 
```
を書きましょう。

```swift
StationList.register(UINib(nibName: "StationTableViewCell", bundle: nil), forCellReuseIdentifier: "StationTableViewCell")
```
上の一文は.xibを利用するときに出てくる違いです。xibを使わないと`UITableView`も`UITableViewCell`も同じstoryBoard内にいるのでいちいちこのcell使うことを知らせる一文が必要ありません。しかし、今回は`UITableView`がどのCellを使っていいのかわからなくなるので定義する必要があります。

最後の方にある３つのtableViewを名前に含む関数は`UItableView`を使用する上では基本的になくてはならないものです。上から順に

- セクションの数を明示する
- セクションごとに何個のcellを表示するのか
- cellに何を表示するのか

に関係することを記述する場所となっています。

#Buildしてみましょう
<img width="355" alt="スクリーンショット 2019-02-17 19.28.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/176180/850b3c47-b2a3-7d8d-0898-260551cc97f0.png">
このように表示されました。見た目は味気ないので修正したい人は修正して遊んでみてください。とりあえず
`.xibを用いたUITableViewCell`の作成は行うことができました。

何か詰まった箇所があれば下のGitHubから確認してみてください。
https://github.com/takumaosada/customCellTutorial

このコードの続きでAPIを利用して一覧表示しているものも記事として投稿しています。よかったら確認してください。https://qiita.com/ostk0069/items/385acd1875c0d3e3277f