Delegateとは:委譲パターンとiOSでの動作

著者: IT Sectr 公開日: 2026-03-17 読了時間: 10 分

Delegateは、あるオブジェクトが事前に定義されたメソッドを持つプロトコルを通じて、別のオブジェクトにタスクの実行を委譲するデザインパターンです。iOS開発において、DelegateはCocoa Touchの基本的なパターンの1つであり、送信者と受信者の直接的な結合なしに非同期通知を行うために使用されます。Apple Documentation(2025)によると、委譲はFoundationとUIKitでテーブルイベント、ネットワークリクエスト、位置情報管理の処理に使用されています。このパターンはコンポーネントの疎結合とコードの再利用を保証します。

重要なポイント

  • Delegateは、オブジェクトがプロトコルを通じて別のオブジェクトにイベント処理を委ねるパターンです。
  • ProtocolはSwiftで、デリゲートが実装すべき(または実装できる)メソッドのセットを定義します。
  • Weak referenceは、 retain cycleを回避するためにdelegateプロパティに必須です。
  • @objc optionalを使用すると、プロトコルのメソッドをオプション(実装任意)にできます。
  • URLSessionDelegateは、ネットワークリクエストイベントを処理するための非同期デリゲートです。

Delegateとは?

Delegate(デリゲート)は、特定のプロトコルを実装し、別のオブジェクトのイベントに関する通知を受け取るオブジェクトです。委譲パターンは継承の代替手段です:メソッドをオーバーライドするためにサブクラスを作成する代わりに、オブジェクトはイベント処理を外部オブジェクトに委譲します。iOSでは、委譲は必須メソッドとオプションメソッドを持つSwiftプロトコルを通じて実装されます。delegateプロパティは常にweak varとして宣言され、オブジェクト間の循環参照を防ぎます。

Delegateプロトコルの定義

デリゲートプロトコルは、オブジェクト間の相互作用の契約を定義します。必須メソッドはデリゲートによって実装される必要があり、そうでなければコードはコンパイルされません。オプションメソッドは@objc optional属性でマークされ、デリゲートが関連するイベントにのみ応答できるようにします。メソッド名は規約に従います:最初のパラメータは送信者オブジェクト、2番目はイベントデータです。例えば、tableView(_:didSelectRowAt:)は、送信者がUITableViewであり、データが選択された行のインデックスであることを示します。

swift
// Delegateプロトコル
protocol DownloadManagerDelegate: AnyObject {
    func downloadManager(_ manager: DownloadManager,
                          didFinishWith data: Data)
    func downloadManager(_ manager: DownloadManager,
                          didFailWith error: Error)

    @objc optional func downloadManager(_ manager: DownloadManager,
                                didUpdateProgress progress: Float)
}

// Delegateを使用するクラス
class DownloadManager {
    weak var delegate: DownloadManagerDelegate?

    func startDownload(from url: URL) {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let self else { return }
            if let error = error {
                self.delegate?.downloadManager(self, didFailWith: error)
            } else if let data = data {
                self.delegate?.downloadManager(self, didFinishWith: data)
            }
        }.resume()
    }
}

デリゲートへの弱参照

delegateプロパティは、 retain cycleを防ぐためにweak varとして宣言する必要があります。参照が強参照であった場合、デリゲートと委譲元オブジェクトは互いに保持し合い、ARCはそれらのメモリを解放できなくなります。デリゲートプロトコルはAnyObject(クラスのみ)を継承し、weakの使用を可能にします。構造体と列挙型は値 semantics のためデリゲートになることはできません。値型の代替手段はコールバッククロージャです。

swift
class ViewController: DownloadManagerDelegate {
    let manager = DownloadManager()

    override func viewDidLoad() {
        super.viewDidLoad()
        manager.delegate = self // weak — retain cycleなし
        manager.startDownload(from: url)
    }

    func downloadManager(_ manager: DownloadManager, didFinishWith data: Data) {
        processData(data)
    }

    func downloadManager(_ manager: DownloadManager, didFailWith error: Error) {
        showError(error)
    }
}

iOSでのDelegateパターンの仕組み

Delegateパターンは1対1で機能します:1つの送信者オブジェクトは特定の時点で1つのデリゲートしか持つことができません。イベントが発生すると、送信者はデリゲートが設定されているかどうかを確認し、対応するプロトコルメソッドを呼び出します。直接呼び出しに対する利点は、送信者がデリゲートの型を知らず、プロトコルに準拠していることだけを知っていることです。これはSOLIDの依存関係逆転の原則(DIP)に準拠しています。

デリゲートのライフサイクル

デリゲートは代入によって割り当てられます:someObject.delegate = self。デリゲートが解放されると、weak semanticsによりプロパティは自動的にnilになります。デリゲートメソッドを呼び出す前に、オプショナルチェイニングを通じてデリゲートがチェックされます:delegate?.method()。delegateがnilの場合、呼び出しはクラッシュせずに無視されます。オプションのプロトコルメソッドについては、追加のチェックが使用されます:delegate?.responds(to: #selector(...))。ただしSwiftでは、このチェックは通常、オプショナルメソッド宣言を通じて暗黙的に行われます。

Delegateによる非同期通知

マルチスレッド環境では、デリゲートは非同期結果の返却に使用されます。URLSessionは、データ受信時、タイムアウト時、認証エラー時に呼び出されるメソッドを持つURLSessionDelegateを提供します。デリゲートメソッドはURLSessionのバックグラウンドキューで実行されるため、UI更新のためにはメインキューへのディスパッチが必要です。非同期デリゲートは呼び出しスレッドをブロックせず、他のタスクを続行できます。

swift
class NetworkService: NSObject, URLSessionDataDelegate {
    private lazy var session = URLSession(
        configuration: .default,
        delegate: self,
        delegateQueue: OperationQueue()
    )
    private var receivedData = Data()

    func urlSession(_ session: URLSession,
                    dataTask: URLSessionDataTask,
                    didReceive data: Data) {
        receivedData.append(data)
        let progress = Float(receivedData.count) / Float(expectedSize)
        DispatchQueue.main.async {
            self.progressHandler?(progress)
        }
    }

    func urlSession(_ session: URLSession,
                    task: URLSessionTask,
                    didCompleteWithError error: Error?) {
        if let error = error {
            delegate?.networkService(self, didFailWith: error)
        } else {
            delegate?.networkService(self, didReceive: receivedData)
        }
    }
}

Delegate vs Callback:アプローチの比較

DelegateCallbackは同じ問題(非同期通知)を解決しますが、方法が異なります。Delegateは名前付きメソッドを持つプロトコルを使用し、Callbackはコンテキストキャプチャを持つクロージャを使用します。選択は、イベントの数、シグネチャの複雑さ、アーキテクチャの好みに依存します。Appleは、複数のイベントを持つAPIにはDelegate(UITableView — 20以上のメソッド)を、1回限りの完了にはCallbackを推奨しています。

Delegateが勝る場合

Delegateは、単一ソースからの複数の異なるイベントを処理する場合に適しています。例えば、CLLocationManagerは、位置情報の変更、許可エラー、ジオフェンスの出入り、サービスのステータス変更をデリゲートに通知します。各イベントは、明確な名前と型付けされたパラメータを持つ個別のプロトコルメソッドです。Delegateは動作設定(should、will、didメソッド)にも便利です。

Callbackが勝る場合

Callbackは、単一の結果を持つ1回限りのリクエストに対してよりシンプルです。URLSession.dataTaskのCompletion handlerは、呼び出し箇所で少なくとも3つのプロトコルメソッドに対して1行で済みます。Callbackは関数型チェーン(map、flatMap、async/await)にもより自然です。ただし、2〜3レベルを超えるネストでは、CallbackはCallback Hellになりますが、Delegateは常にフラットなままです。

iOS SDKの組み込みDelegate

iOS SDKには、さまざまなサブシステム用の数十の組み込みデリゲートプロトコルが含まれています。それぞれが特定の相互作用シナリオ用に設計されています。Apple Documentation(2025)によると、最も使用されているデリゲートは、UITableViewDelegate、UITextFieldDelegate、CLLocationManagerDelegate、URLSessionDelegate、UNUserNotificationCenterDelegateです。これらのプロトコルには、必須レベルの異なる3〜30のメソッドが含まれています。

UITableViewDelegate

UITableViewDelegateは、テーブルセルの外観と動作を管理します。行の選択処理、セルの高さ設定、カスタムヘッダー/フッタービュー、スワイプアクションのためのメソッドが含まれています。すべてのプロトコルメソッドはオプションであり、必要な機能のみを実装できます。デリゲートがない場合、テーブルはデフォルト設定で動作します。歴史的に、デリゲートはUITableViewDataSourceと組み合わされていました。

URLSessionDelegate

URLSessionDelegateは、HTTPリクエストの詳細な制御を提供します。デリゲートメソッドは、サーバー応答の受信時、データ到着時、ダウンロード完了時に呼び出されます。特殊化されたサブプロトコルURLSessionTaskDelegateとURLSessionDataDelegateは、特定のタスクタイプの基本機能を拡張します。デリゲートは、バックグラウンドダウンロード、SSL証明書、カスタムリダイレクト処理をサポートするために必要です。

Delegateメソッド数目的
UITableViewDelegate25テーブルの外観と操作
UITextFieldDelegate8テキスト入力とキーボード処理
CLLocationManagerDelegate12位置情報の更新とジオフェンス
URLSessionDelegate6HTTPセッションと証明書管理
UNUserNotificationCenterDelegate4フォアグラウンドでのプッシュ通知処理

Delegateを使用したメモリ管理

メモリ管理は、iOSでデリゲートを使用する際の重要な側面です。ARC(自動参照カウント)はメモリを自動的に管理しますが、weak/unowned参照の適切な使用が必要です。ルールに違反すると、メモリリークや早期解放が発生します。strongとして宣言されたデリゲートは、デリゲートの所有者が委譲元オブジェクトへの参照も保持している場合、 retain cycleを引き起こします。

DelegateによるRetain Cycle

Retain cycleは、オブジェクトA(所有者)が自身をオブジェクトBのデリゲートとして設定し、Bがデリゲートへの強参照を保持する場合に発生します。:ViewControllerがURLSessionを作成し、自身をセッションのデリゲートとして設定しますが、delegateQueueが指定されていない場合、URLSessionはデフォルトでデリゲートへの強参照を保持します。解決策は、デリゲート参照タイプ(weakまたはstrong)についてAPIドキュメントを常に確認し、deinitでデリゲートを明示的にnilにすることです。

swift
class SafeViewController: UIViewController {
    private var session: URLSession?
    private var service: NetworkService?

    override func viewDidLoad() {
        super.viewDidLoad()
        service = NetworkService()
        service?.delegate = self
    }

    deinit {
        // deinitでdelegateをnilに設定 — best practice
        service?.delegate = nil
        session?.invalidateAndCancel()
    }
}

// NSObjectを介したweak delegate付きURLSession
class WeakDelegateSession: NSObject {
    private weak var delegate: URLSessionDelegate?

    func createSession() -> URLSession {
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        return URLSession(
            configuration: .default,
            delegate: self,
            delegateQueue: queue
        )
    }
}

呼び出し前の安全なデリゲート確認

デリゲートメソッドを呼び出す前に、デリゲートが存在し(nilではなく)、呼び出されたメソッドを実装していることを確認する必要があります。必須プロトコルメソッドの場合、チェックは不要です。コンパイラが実装を保証します。オプションメソッドの場合は、respond(to:)またはオプショナルチェイニングを使用します。デリゲートが解放された場合、weak参照は自動的にnilになり、デリゲート呼び出しは無視されます。これは追加の処理を必要としない安全な動作です。

Delegate実装における一般的なエラー

開発者は、特にiOS学習の初期段階において、Delegateパターンを使用する際にしばしばエラーを犯します。最も一般的なものは次のとおりです:strongデリゲートによる retain cycle、delegate?.method()の呼び出し忘れ、誤ったプロトコルメソッドシグネチャ、操作開始後のデリゲート設定、マルチスレッドの衝突。各エラーとその防止方法を見てみましょう。

Weakの代わりにStrong参照

最も重大なエラーは、delegateプロパティをweak varの代わりにstrong varとして宣言することです。これにより、デリゲートと委譲元オブジェクトの両方が解放できない retain cycleが発生します。結果:メモリリーク、アプリの遅延、隠れたバグ。解決策:デリゲートには常にweak varを使用し、プロトコルをAnyObjectから継承させて、値型がデリゲートとして使用されるのを防ぎます。

操作開始後のデリゲート設定

非同期メソッドを呼び出した後にデリゲートを設定すると、最初のイベントが失われる可能性があります。:manager.delegate = selfを割り当てる前にstartDownload()を呼び出すと、ダウンロードが同期的または非常に高速に実行された場合に完了コールバックが失われます。解決策:非同期メソッドを呼び出す前にデリゲートを設定し、プロトコルコメントで初期化順序を文書化します。

よくある質問

なぜdelegateはweakとして宣言されるのですか?

Weakは、デリゲートと委譲元オブジェクト間の retain cycleを防ぎます。参照が強参照であった場合、オブジェクトは互いに保持し合い、ARCはそれらを解放できなくなります。weak参照は、デリゲートが解放されると自動的にnilになります。これはObjective-Cの登場以来の標準的なCocoa Touchのプラクティスであり、後方互換性のためにSwiftでも維持されています。

delegateとdataSourceの違いは何ですか?

Delegateはイベントを処理し、動作を管理します(セルの高さ、タップへの応答)。DataSourceは表示用のデータを提供します(行数、セル)。デリゲートは “どのように?” という質問に答え、dataSourceは “何を?” という質問に答えます。iOSでは、両方ともプロトコルを通じて実装され、多くの場合同じコントローラ内にありますが、概念的に分離されています。

structをデリゲートとして使用できますか?

いいえ、プロトコルがAnyObject(クラスプロトコル)を継承している場合、使用できません。weak参照は参照型(クラス)でのみ使用できます。値型(struct、enum)の場合は、コールバッククロージャまたは個別のラッパークラスを使用してください。プロトコルを制御できる場合は、AnyObjectの継承を避けることができますが、その場合weakは禁止されます。weakデリゲートとstructデリゲートの間で意識的に選択してください。

responds(to:)メソッドとは何ですか?なぜ必要ですか?

responds(to:)は、オブジェクトが指定されたセレクタを実装しているかどうかをチェックするNSObjectProtocolのメソッドです。呼び出し前にオプションの@objcプロトコルメソッドをチェックするために使用されます。このチェックがないと、実装されていないオプションメソッドを呼び出すとNSInvalidArgumentExceptionが発生します。Swiftでは、@objc optionalを持つプロトコルの場合、チェックはオプショナルバインディングを通じて暗黙的に行うことができます。

Delegateはシングルトンですか?

いいえ、delegateは委譲パターンであり、シングルトンではありません。シングルトンとは異なり、デリゲートは実行時に置き換えることができ、各委譲元オブジェクトに対して単一のインスタンスとして存在します。1つのオブジェクトが複数の送信者のデリゲートになることができます。シングルトンは単一のクラスインスタンスを保証する生成パターンであり、委譲とは関係がありません。

まとめ

  • Delegateは、オブジェクトが型付けされたメソッドを持つプロトコルを通じて、別のオブジェクトにイベント処理を委譲するパターンです。
  • Weak varは、 retain cycleとメモリリークを防ぐためにdelegateプロパティに必須です。
  • Protocolは、必須およびオプション(@objc optional)の委譲メソッドを定義します。
  • iOS SDKには、UITableViewDelegate、URLSessionDelegate、CLLocationManagerDelegateなど15以上の組み込みデリゲートプロトコルが含まれています。
  • Delegateは、単一ソースからの3つ以上の異なるイベントがある場合(CLLocationManager)、callbackよりも推奨されます。
  • 非同期デリゲートは、スレッドをブロックせずにデータと進捗を受け取るためにURLSessionで使用されます。
  • 非同期操作を開始する前にデリゲートを設定し、安全なメモリ管理のためにdeinitでnilにします。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください