🐾

Delegateパターンを具体例を踏まえて説明する

2022/11/09に公開

初めに

最近、プログラミングスクールでメンターの副業を始めました。
ほとんど生徒さんがDelegateの理解に躓いています。(僕も躓きました笑)
僕はこんな感じで理解してるよーっていうのを記事にしてみました。

Delegateとは?

Delegateは直訳すると、代理とか移譲するみたいな意味です。
何を移譲するかというと、「処理の内容」です。

UITableViewの場合

具体例として、最初にDelegateに触れるであろうUITableViewで説明します。
UITableViewのセルをタップした時の処理は、tableView(_ UITableView: UITableView, didSelectRowAt indexPath: IndexPath)の中に書きますよね?
この場合、「関数の呼び出しはUITableView側で行われ、処理の内容は呼び出し側で決める」ことになります。
この「処理の内容は呼び出し側で決める」を移譲すると言っているわけですね。
(呼び出しは次節で説明します。)

実際に使用する時、下記のように関数の定義だけで呼び出しは行なっていないはずです。

extension ViewController: UITableViewDelegate {

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    }
}

// 上記関数を下のように実行はしていない
sayHello()

tableView.deleagte = selfについて

tableView.deleagte = selfこの1行に多くの初学者が疑問を思ったはずです。
これは何をしているかというと、UITableViewのdelegateというプロパティに呼び出しているクラスを代入しています。
(selfはほとんどの場合ViewControllerでしょう。正確に言うと、UIViewControllerのサブクラス)

セルをタップしたときに、UITableView側では、下記のように呼び出しが行われます。

// 実際の実装を見たことはないですが、おそらくこんな感じ
delegate?.tableView(self, didSelectRowAt: indexPath)
// 注意: ここのselfは、呼び出しているUITableViewが入ります。

このdelegateにはtableView.deleagte = selfで代入したself(実行するクラス, ViewControllerとか)が入っており、
そこに定義されているtableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)が実行されることになります。

class HogeViewController: UIViewController {
    let tableView = UITableView()
    
    override func viewDidLoad() {
        tableView.delegate = self  
    }
}

extension HogeViewController: UITableViewDelegate {
    // UITableViewからdelegateプロパティを経由して呼び出される
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

    {
}

// セルがタップされたとき、UITableView側で、
// delegate?.tableView(self, didSelectRowAt: indexPath)が実行される。
// delegateには、delegate = selfで代入したHogeViewControllerが入っている。
// → HogeViewContollerに定義されているtableView(self, didSelectRowAt: indexPath)が実行される

初心者あるあるですが、tableView.deleagte = selfを書き忘れると、tableViewのdelegateがnilであるためtableView(_ UITableView: UITableView, didSelectRowAt indexPath: IndexPath)が実行されません。

tableView.delegateに代入できる型

公式ドキュメントの説明です。

var delegate: UITableViewDelegate?
// The object that acts as the delegate of the table view.

protocol UITableViewDelegate
// Methods for managing selections, configuring section headers and footers,
// deleting and reordering cells, and performing other actions in a table view.

delegateの型はUITableViewDelegate?となっていますね。それと、UITableViewDelegateはprotocolであることがわかりました。
つまり、UITableViewDelegateに準拠しているクラスであれば、UITableViewのdelegateに代入可能となります。
逆を言うと、UITableViewDelegateに準拠していなければ代入することができません。extensionで継承している箇所を消すと下記エラーがでました。

Cannot assign value of type '{ViewController名}' to type '(any UITableViewDelegate)?'

まとめ

  • Delegateメソッドの呼び出しは、処理を移譲する側(UITableViewとか)が行う
  • Delegateメソッドの処理内容は、処理を移譲される側(UIViewControllerとか)が決める
  • 呼び出しは、移譲する側のdelegateプロパティを介して行われる
    • delegate?.tableView(self, didSelectRowAt: indexPath)
  • そのため、移譲するクラスのdelegateプロパティに移譲されるクラスをセットする
    • tableView.delegate = self

最後に

説明は移譲(以上)です!w
Delegateは自作するのが一番理解が進むと思っています。機会があれば、作る所も記事にしようと思います。(よく見るけど)

気になる点があれば、コメントください。

GitHubで編集を提案

Discussion