【swift】デリゲートって何だ?出来るだけ分かりやすく解説します

もくじ

毎度どうもこんにちは。iOSをメインに開発しているロッキーカナイです。

デリゲートってどんな処理か想像できますでしょうか?以前は全く分からずに避けていたのですが、iOS開発をするとUITableViewやUITextFieldなどでデリゲートメソッドを実装する事が多く、今ではマブダチになりました!

今日は、デリゲートってなんぞや?と思われている方向けに説明します。よって難しい用語や抜きにして簡潔にし、イメージを掴んでもらおうと考えております。尚、UITableViewを例にして解説します。

デリゲートとは

デリゲートとはプロコトルを用いたデザインパターンで「あるクラスは、他のクラスのインスタンスに、処理を任せることができる」ものになります。

※プロトコルってなんぞや?という方は以前書いた、【swift】プロトコルを使ってみようの記事を参考にしてみてください。ざっくり言ってしまうと、プロコトルとは必ず定義したプロパティやメソッドは必ず実装しなくてはならない手続き書になります。

具体例

分かりやすく例を挙げると、UITableViewを表示するUIViewControllerがあるとします。UITableViewだけでは、UIとして完成しません。なぜならテーブルのセクション数やセル数やセル自体がないからです。その不足した情報をUITableViewが保持しているプロトコルのUITableViewDelegateやUITableViewDataSourceで他のクラスに処理をしてもらう事で完成させるのですが、この時の「他のクラスに処理をしてもらう」というのがデリゲートになります。なんとなくイメージ出来ましたでしょうか?

デリゲートを実装するには

登場人物は3つです。

  1. プロトコル
  2. 処理を任せるクラス
  3. 処理を任せられるクラス

UITableViewの場合に当てはめると、

  1. プロトコルがUITableViewDelegateとUITableViewDataSource
  2. 処理を任せるクラスがUITableView
  3. 処理を任せられるクラスがUIViewController

UITableViewのデリゲート処理を見てみよう

1.プロコトル(UITableViewDelegateとUITableViewDataSource

UITableViewDelegate

@available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)

・didDeselectRowAt セルがタップさてた処理をしてもらうデリゲートメソッド

UITableViewDataSource

@available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int

@available(iOS 2.0, *)
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

・numberOfRowsInSection 各セクションのセル数を返してもらうデリゲートメソッド

・cellForRowAt 各セルを作って返してもらうデリゲートメソッド

2.処理を任せるクラス(UITableView)

フレームワーク内なのでコードの確認はできませんが、テーブルを生成する際に必要な情報(セル数やセル自体)をプロコトルを適用したクラスからデリゲートメソッドを通じて取得しています。

class TableView {
    var delegate: UITableViewDelegate?
    
    func createTable() {
        // テーブルを生成
        // ...
        
        /*
         自身が保持しているUITableViewDataSourceプロコトルを適用したデリゲートメソッドを実装したUIViewControllerがあれば,
         セクションのセル数を返してもらう
         プロコトルで定義されてりるメソッドは、
         func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
         */
        let cellNum = delegate?.tableview(tableView, numberOfRowsInSection: 0)
    }
}

このような感じでやっていると思います。

3.処理を任せられるクラス(UIViewController)

class ViewController : UIViewController, UITableViewDelegate, UITableViewDataSource { // <-①
    var tableView: UITableView = UITableView()

  override func viewDidLoad() {
        super.viewDidLoad()

        // UITableViewDelegateとUITableViewDataSourceで保持しているプロコトルは自身が実装しますよと設定
        tableView.delegate = self // <-②
        tableView.dataSource = self // <-②
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // <-③        // セルタップしたらする処理
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // <-③
        // テーブルビューのセクション数
        return 1
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // <-③
        // テーブルビューのセル
        return UITableViewCell()
    }
}

ここでは順序を説明します。

  1. UIViewControllerのクラス定義で、UITableViewで保持しているプロコトルの UITableViewDelegateとUITableViewDataSourceを適用します。
  2. UITableViewで保持しているプロコトルの UITableViewDelegateとUITableViewDataSourceは自身(UIViewController)が実装しますと設定
  3. UITableViewDelegateとUITableViewDataSourceのプロコトルメソッドを実装

図解

まとめ

いかがでしょうか?なんとなく分かって頂けたでしょうか?

冒頭でも説明しましたがiOSではデリゲートを用いたプログラムが多く存在しておりますので、避けては通れない道です。はじめはわからなくても徐々に慣れて、ああこういうものかと分かって頂ければ幸いです。

関連する記事

もっと見る