サイト名変更・お引越しのお知らせ

【入門】iOS delegateを図を用いてわかりやすく使い方を解説

iOS開発において重要なdelegateについて解説します。

環境

  • swift 5.7
  • Xcode 14.0.1
  • macOS 12.6 Monterey

delegateとは

delegateとはあるクラスの処理をdelegateが橋渡しとなり違うクラスに処理を渡すことです。

もしJavaをやっている方であればinterfaceを想像してもらえればそれと同様の意味です。

メモ

ちなみにdelegateという英単語は「委譲する・委任する」という意味なので、

この意味で考えてもらっても想像しやすいかもしれません。

現時点でわからなくてもこれから例と一緒に詳しく説明します!

サンプルコードでdelegateを理解

理解を深めていくために、実際にサンプルコードを書いてみましょう。

ボタンを押すと1秒後にアラートが表示されるサンプルアプリで説明していきます。

完成イメージ

完成イメージはこちらです!

簡単なアプリで解説していきます。

全体のイメージ

今回は要素が3つあります。

  • ViewController: ボタンのタップイベントを拾いアラートを表示
  • TimeManager: 時間を管理
  • TimeManagerDelegate: 時間が経過したことを知らせる

TimeManagerDelegateは ViewControllerが実装し、時間が経過した通知を受け取れるようにします。

それぞれの関係は下の図になります。

class_relation

  1. ViewControllertappedButton() でタップイベントを拾い TimeManagerwaitOneSecond() を呼び出す(TimeManager では時間を計測し始める)
  2. 1秒が経過されると TimeManager ではTimeManagerDelegatetimeIsUp() を呼び出す

こうすることでdelegateを通じて ViewController に処理を渡すことができます。

delegateを実装

それでは上の説明をコードで実装をしていきます。

まずは全体のコードを見てみましょう。

import UIKit

class ViewController: UIViewController, TimeManagerDelegate {

    let timeManager = TimeManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        // delegateをselfに指定
        timeManager.delegate = self
    }

    // ボタンのタップイベント
    @IBAction func tappedButton(_ sender: Any) {
        // ① TimeManagerのwaitOneSecond()を呼び出す
        timeManager.waitOneSecond()
    }

    // TimeManagerDelegateの関数
    func timeIsUp(message: String) {
        // ③ TimeManagerが呼び出す
        let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
        let action = UIAlertAction(title: "OK", style: .default, handler: nil)
        alert.addAction(action)
        present(alert, animated: true)
    }
}

class TimeManager {
    // delegateを呼び出せるようにプロパティで持っておく
    weak var delegate: TimeManagerDelegate? = nil

    func waitOneSecond() {
        Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
            // ② 1秒が経過したらTimeManagerDelegateのtimeIsUp()を呼び出す
            self?.delegate?.timeIsUp(message: "1秒たちました")
        }
    }
}

protocol TimeManagerDelegate: NSObjectProtocol {
    func timeIsUp(message: String)
}

それでは1つ1つ見ていきましょう。

class ViewController: UIViewController, TimeManagerDelegate {

    let timeManager = TimeManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        // delegateをselfに指定
        timeManager.delegate = self
    }
}

上記の1行目で TimeManagerDelegate に準拠させています。

こうすることでViewControllerUIViewControllerとしても扱えるしTimeManagerDelegateとしても扱えるようになります。

次に viewDidLoad()timeManagerdelegate にselfを指定することでdelegate関数が呼ばれるようにします。

これができるのはdelegate の型がTimeManagerDelegateであるためです

@IBAction func tappedOneButton(_ sender: Any) {
    // ① TimeManagerのwaitOneSecond()を呼び出す
    timeManager.waitOneSecond()
}

次は先ほどのイメージ画像の①に該当するボタンのタップイベントです。
ここでは timeManagerwaitOneSecond() 関数を呼び出しているだけですね。

説明は省略していますが今回はStoryBoardを使ってUIButtonを配置しています。

func waitOneSecond() {
    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { [weak self] _ in
        // ② 1秒が経過したらTimeManagerDelegateのtimeIsUp()を呼び出す
        self?.delegate?.timeIsUp(message: "1秒たちました")
    }
}

イメージ画像の順番通りに説明するためソースコードが少し飛びますが、
イメージ画像の②に該当する TimeManagerwaitOneSecond() 関数です。

ここでは Timer クラスを使用して1秒が経過した後に delegatetimeIsUp() を呼んでいます。

// TimeManagerDelegateの関数
func timeIsUp(message: String) {
    // ③ TimeManagerが呼び出す
    let alert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
    alert.addAction(action)
    present(alert, animated: true)
}

次は ViewController で実装している TimeManagerDelegatetimeIsUp() 関数です。
イメージ画像では③に該当します。

ここは先ほど見たように TimeManager が1秒経過後に呼び出しており、
ViewController に処理を任せています。

それではここでビルドしてみましょう。

完成

こんな動きになっていれば成功!

うまく処理が移譲できています。

まとめ

今回はサンプルを用いることでdelegateを使った処理の譲渡を見ることができたかと思います。

ただdelegateの理解はiOS開発の中でも大きなハードルであると考えています。

このような概念を理解することは自分の中でのイメージが重要ですので、
実装する際には処理を譲渡する役( TimeManager )、処理を譲渡される役( ViewController )、
処理の橋渡し役( TimeManagerDelegate )の3つの役者を整理することが大切です。