コードでカスタムセルを使う時register(_:forCellReuseIdentifier:)関数を入れそびれていた

#前提
Xcode9.2
Swift4


#問題
列ごとに表示するセルを決めるデリゲートメソッドを書いて、その列にどのセルを使うかというのを決めると思います

```swift
extension ListViewController: UITableViewDelegate, UITableViewDataSource {

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(ListTableViewCell.self), for: indexPath) as? ListTableViewCell else {
            fatalError("The dequeued cell is not instance of MealTableViewCell.")
        }

///ここ以下省略
```

ここで落ちてしまう

```swift
guard let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(ListTableViewCell.self), for: indexPath) as? ListTableViewCell
```


## エラーメッセージ

```swift
reason: 'unable to dequeue a cell with identifier Todolist_firebase.MyCell - 
must register a nib or a class for the identifier or connect a prototype cell in a storyboard'
```

##原因と解決策
下記の入れ忘れ

```
tableView.register(ListTableViewCell.self, forCellReuseIdentifier: NSStringFromClass(ListTableViewCell.self))
```

[register(_,identifier)のApple公式ドキュメント](https://developer.apple.com/documentation/uikit/uitableview/1614888-register)ではここで紹介されています

```
func register(_ cellClass: AnyClass?, 
forCellReuseIdentifier identifier: String)
```

```
セルを作成する前に、このメソッド（_：forCellReuseIdentifier :)を呼び出して、新しいセルをつくることをテーブルビューに伝えます。 指定されたタイプのセルが現在再利用キューにない場合、テーブルビューは提供された情報を使用して新しいセルオブジェクトを自動的に作成します。
```

つまり第一引数にはこのテーブルビューで使うcellのクラスを登録し、第二引数では再利用する際の名札的な立ち位置でString型の名前を入れてねということなのでしょう


[dequeueReusableCell(withIdentifier:for:)のアップル公式のドキュメント](https://developer.apple.com/documentation/uikit/uitableview/1614878-dequeuereusablecell)
再利用可能なテーブルビューセルオブジェクトを返し、それをテーブルに追加する関数ですね
この関数は第一引数がString型のidentifierで第二引数がindexPathなので何番目のセルを対象としているのかという数字が返ってきます
第一引数に着目すると型はString型になっており、上記のregister関数でstringで登録したものを再利用できるようにしているのですね

```
func dequeueReusableCell(withIdentifier identifier: String, 
                     for indexPath: IndexPath) -> UITableViewCell
```

公式ドキュメントではわざわざ黄色く囲まれたImportantのところで
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/176479/a9139a0e-9da7-e9da-a7b1-8ba002476576.png)

```
重要

このメソッドを呼び出す前に、register（_：forCellReuseIdentifier :)またはregister（_：forCellReuseIdentifier :)メソッドを使用してクラスまたはnibファイルを登録する必要があります。
```
と書いてありました


## コード全体
一部省略してます
ちなみに何故`register`関数の第二引数で`NSStringFromClass(ListTableViewCell.self)`このようにしているかというと、`NSStringFromClass`関数は引数で入れたクラスをStringにして返してくれる関数だからです

```
例
NSStringFromClass(ListTableViewCell.self)
↓
"Todolist_firebase.ListTableViewCell"
```


```swift
class ListViewController: UIViewController {
    var tableView = UITableView()
    override func viewDidLoad() {
        super.viewDidLoad()

        //テーブルビュー
        tableView = UITableView(frame: self.view.frame, style: .plain)
        tableView.rowHeight = 100
        tableView.delegate = self
        tableView.dataSource = self
        //NSStrignFromClassはクラスの名前をStringで返してくれる
        tableView.register(ListTableViewCell.self, forCellReuseIdentifier: NSStringFromClass(ListTableViewCell.self))
        self.view.addSubview(tableView)
    }

}

extension ListViewController: UITableViewDelegate, UITableViewDataSource {
    
    //セクションの数を設定
    func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }
    
    //行数 セクションによって行数が違う場合はsectionで場合分けをするUITableViewDataSource
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }
    //列ごとに表示するセルを決めるデリゲートメソッド
    //UITableViewDataSource は主に Table View が表示するデータを与えるものです。
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: NSStringFromClass(ListTableViewCell.self), for: indexPath) as? ListTableViewCell else {
            fatalError("The dequeued cell is not instance of MealTableViewCell.")
        }

        let item = items[indexPath.row]
        cell.nameLabel.text = item.title     
        return cell
    }
}

class ListTableViewCell: UITableViewCell {
    
    //MARK: Properties
    var nameLabel: UILabel!
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        self.commonInit() 
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.addSubview(nameLabel)
        nameLabel.frame = CGRect(x: 110, y: 0, width: frame.width - 100, height: frame.height)
        
    }
    
    //MARK : method
    private func commonInit() {
        self.createNameLabel()
    }
    private func createNameLabel() {
        nameLabel = UILabel(frame: CGRect.zero)
        nameLabel.textAlignment = .left
        nameLabel.font = UIFont.systemFont(ofSize: 20)
    }
    

}
```

##おまけ
Appleのドキュメント曰く

```
指定した識別子のクラスを登録し、新しいセルを作成する必要がある場合、init（style：reuseIdentifier :)メソッドを呼び出してセルを初期化します。 
既存のセルが再利用可能な場合、このメソッドは代わりにセルのprepareForReuse（）メソッドを呼び出します。
```

とのことで、`prepareForReuse()`関数がいつ使われるのかがドキュメントを確認することでわかりました