Referenceを読んでUITableViewの基本処理について考える

`UITableView`を`ViewController`で使う際、`UITableViewDelegate`や`UITableViewDataSource`protocolを適用させて、protocolが要求するmethodを書き、`tableView`のdelegateやdatasouceを`ViewContoller`(=self)に当てるかと思います。

今まで理解が曖昧なままに書いていましたが、よくよく考えると「なぜこういう風に書くんだ」と疑問に思ったので、自分なりに噛み砕いて考え方の流れについてまとめてみました。

今回はReferecneを主に参考にしていますが、[こちらの解説動画](https://www.youtube.com/watch?v=KmTEMu2vbAY&t=1045s)が全体感を掴み安くオススメです。

#目次
* 前提確認
* 考え方のスタート地点
* UITableViewを使うとはどういうことなのか
* UITableViewDataSource protocol
* 考え方の整理
* まとめ

#前提確認
MacOS Catalina 10.15.4
Xcode 12.1
Swift version 5

今回は以下の`UITableView`を使った最低限のコードをもとに考えていきます。

疑問点をコメントしています。

```swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource { //←なぜUITableViewDataSourceを適用？

    @IBOutlet weak var tableView: UITableView!

        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.dataSource = self //←これが最大の謎
        }

        //ナニコレ？
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 10
        }

        //ナニコレ？
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
            cell.textLabel?.text = "\(indexPath.row + 1)"
            return cell
        }
    }
```

これでビルドするとこうなります↓
<img width="300" alt="simulator_screenshot_E6960ED6-9477-4EDB-9E9A-8BB3CBB02DB0.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/843253/03b7abdc-5c9c-fbd5-9b74-adc2185438b8.png">


#考え方のスタート地点
まずは「`UITableView`を使う！」ということから考えをスタートしていきます。(当たり前ですが)

「`UITableView`を使うとはどういうことなのか(=何をすることなのか)」についてみていきましょう。

ちょっと哲学的(?)な問いですが、難しい話はしませんのでご安心ください。

#UITableViewを使うとはどういうことなのか

Appleが提供するReferenceを読むと、`UITableView`の概要説明として以下が書かれています。

>Table views on iOS display a single column of vertically scrolling content, divided into rows. 

ざっくり言うと「スクロールできる縦方向の入れ物が、複数の横方向の入れ物に分割されている状態を表示させる」と言ったところでしょうか。

この横方向の入れ物に表示させるデータがあれば、いわゆるcellとして表示します。

ここで大事なのは、あくまで`UITableView`を使うということ、はこれらの「入れ物を表示させている」だけということです。

その入れ物に表示させるデータについて(表示させたいデータはいくつあるのか、データの中身がどうなっているのか等)は、管理していないようです。

では、どこでデータ管理しているのか。

また別のReference("Filing a Table with Data")を見てみると、

>The table view arranges your views onscreen and works with your data source object to keep that data up to date.

とあります。`UITableView`は`data source object`を使って最新のデータを表示しているようです。

今度は「...`data source object`？」となりますね。

同じReferenceを更に読むと、以下の記載があります。

> a data source object—that is, an object that adopts the UITableViewDataSource protocol.

`data source object`とは`UITableViewDataSource`protocolを適用した`object`のようです。

だんだん見えてきましたね。`UITableViewDataSource`protocolについて見る前に、一旦ここまでについてまとめてみます。

「`UITableView`を使うということは、単に横方向に分割された入れ物を表示させるということ。入れ物に表示させたいデータを管理するには、`UITableViewDataSource`protocolを適用させた`data soucre object`を使う必要がある。」

#UITableViewDataSource protocol

さて、`UITableViewDataSource`protocolのReferenceを見てましょう。

>Table views manage only the presentation of their data; they do not manage the data itself. To manage the data, you provide the table with a data source object...

「`UITableView`はデータを表示させるだけで、データ自体を扱わない。データを扱うには`data soucre object`を`UITableView`に渡す必要がある。」書かれています。

これは先ほど見たものと同じ内容ですね。

続きを見ていきましょう。

>A data source object responds to data-related requests from the table. 

このprotocolを適用した`data source object`は、`UITableView`から要求されたデータ関連の情報を返すようになっているようです。

更に読んでいくと、次のような記載があります

>Only two methods of this protocol are required, and they are shown in the following example code.

`UITableView`にデータ関連の情報を送るためには、次の2つメソッドを必ず実行する必要があります。

```swift
// Return the number of rows for the table.→横方向の入れ物はいくつあるか
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
   return 0
}

// Provide a cell object for each row.⇨横方向の入れ物にどんなデータ(=cell)を渡すか
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   // Fetch a cell of the appropriate type.
   let cell = tableView.dequeueReusableCell(withIdentifier: "cellTypeIdentifier", for: indexPath)
   
   // Configure the cell’s contents.
   cell.textLabel!.text = "Cell text"
       
   return cell
}
```

要は`UITableView`に与える情報として、「表示させたいデータ(=cell)はいくつあるか、どういうデータを表示させるか」と言う2つの情報が最低限必要だということです。

逆に言うと、この2つの情報を与えれば、あとは`UITableView`が勝手に表示してくれるということですね。

だいぶ見えてきました。これまで見てきたことを整理して、最初のサンプルコードに戻ってみましょう。


#考え方の整理

これまで見てきたことを整理するとこうなるかと思います。

①`UITableView`を用意する。但し、`UITableView`は与えられたデータを表示させるだけでデータ自体は扱わない
②データを扱うために`UITableViewDataSource`protocolを適用した`data source object`を`UITableView`に渡す必要がある
③`UITableViewDataSource`protocolを適用したobjectは、最低限2つのメソッド実行する必要がある

これを最初のコードに当てはめてみると、

```swift
import UIKit
class ViewController: UIViewController, UITableViewDataSource { //③tableViewに自分自身をdata source objectとして渡すために、`UITableViewDataSource`protocolを適用する

    @IBOutlet weak var tableView: UITableView! 
    //①tableViewは与えられたデータを表示させるだけで、データ自体は扱わない。

        override func viewDidLoad() {
            super.viewDidLoad()
            tableView.dataSource = self 
            //②tableViewがデータを扱うために`UITableViewDataSource`protocolを適用したdata source objectをtableViewに渡す必要がある。今回は自分自身(=ViewController)なのでself。
        }

        //④data source objectとして、tableViewにデータを渡すために必要なメソッド
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return 10
        }

        //④data source objectとして、tableViewにデータを渡すために必要なメソッド
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
            cell.textLabel?.text = "\(indexPath.row + 1)"
            return cell
        }
    }
```

最初の疑問はほとんど解消されたかと思います。

ただ、ここのコードが若干まだ気になります。

```swift
tableView.dataSource = self 
```

「...あれ、tableView.dataSourceって誰だ？？」

これをctrl+クリックでDefinitionに飛んでみると

```swift
open class UITableView : UIScrollView, NSCoding, UIDataSourceTranslating {

(略)

    weak open var dataSource: UITableViewDataSource?
```

と記載されています。

どうやら`UITableView`が持つプロパティの一つで、`UITableViewDataSource`protocolが適用されているようです。

`UITableView`はこれに対してデータを取って来るように処理を行っているんですね。

今回はそのプロパティに対して`UITableViewDataSource`protocolを適用した`ViewController`自身(=self)を設定しているわけです。

これでスッキリ！！！

　　　　　
　　
　　

　

　　
…と言いたいところですが、

「そもそも`UITableView`がデータを管理しないのはなぜ？」という根本的な問いがふと思いつきます。(思いついてしまいました)

ただそれを書くとが長くなってしまうので、最初に紹介した[こちらの解説動画](https://www.youtube.com/watch?v=KmTEMu2vbAY&t=1045s)をご参考ください。分かりやすくまとまっています。m(_ _)m

#まとめ

少し長くなってしまいまいたが、全体的な流れについて大体お分かり頂けたのではないでしょうか。

何となくで処理を書いてしまっていることが多いかもしれませんが、こうして一つ一つ流れを追うと、納得感が出てより使いこなせるかと思います。


私自身`UITableView`に対してずっと苦手意識があったのですが、それを克服するために今回そもそもの処理について整理して言語化してみました。


またその過程で、Referenceを読んで一次情報に当たることの大切さを改めて感じました。

今後も引き続き精進していきます。何かコメントやご指摘あれば幸いです。