Delegateとは?委譲パターンとiOSプロトコル

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

Delegateは、あるオブジェクトがタスクの実行を別のオブジェクトに委譲するデザインパターンです。iOSでは、このパターンはSwiftプロトコルと@protocol Objective-Cを通じて実装されます。委譲はCocoa Touchの基本的なパターンの1つであり、UITableViewDelegate、UITextFieldDelegate、そして何百もの他のApple APIで使用されています。Apple Developer Documentation(2025)によると、UIKitシステムクラスの約70%が継承なしで動作をカスタマイズするためにデリゲートを使用しています。

重要なポイント

  • Delegate — オブジェクトAがプロトコルまたはインターフェースを通じてオブジェクトBにタスクの実行を委譲するパターン
  • Swiftプロトコルは、デリゲートが実装できるまたはしなければならないメソッドのセットを定義します
  • Weak参照は、保持サイクルとメモリリークを防ぐためにデリゲートに必須です
  • UITableViewDelegate — iOSで20以上のオプショナルメソッドを持つ最も一般的なデリゲートの例
  • Observerとの違い: デリゲートは1:1の関係ですが、通知は1:Nの原理で動作します

Delegateパターンとは?

Delegateは、オブジェクトがその責任の一部を別のオブジェクトに委譲できるようにする動作デザインパターンです。子クラスが親メソッドをオーバーライドする継承とは異なり、デリゲートはコンポジションを使用します。所有者オブジェクトはデリゲートへの参照を保持し、特定のポイントでそのメソッドを呼び出します。

デリゲートはプロトコルを定義します — デリゲートが実装できるメソッドのセットです。メソッドは必須(required)とオプショナル(optional)に分けられます。Swiftでは、オプショナルなプロトコルメソッドは@objc optionalキーワードでマークされます。

デリゲートの仕組み

オブジェクトA(所有者)はdelegateプロパティ — オブジェクトB(デリゲート)への弱参照(weak reference)を含みます。イベントが発生すると、AはBが対応するプロトコルメソッドを実装しているか確認し、それを呼び出します。弱参照は必須です。これがないと、所有者が強い参照で保持するため、デリゲートはメモリから解放されません。

Swift
protocol LoaderDelegate: AnyObject {
    func loaderDidStart(_ loader: DataLoader)
    func loader(_ loader: DataLoader, didLoad data: Data)
    func loader(_ loader: DataLoader, didFailWith error: Error)
}

class DataLoader {
    weak var delegate: LoaderDelegate?
    
    func start() {
        delegate?.loaderDidStart(self)
        // 非同期ローディング
    }
}

DataLoaderクラスはLoaderDelegateプロトコルを定義し、ロードライフサイクルの重要なポイントでデリゲートメソッドを呼び出します。AnyObjectは、プロトコルがクラスによってのみ実装できることを保証します — これは弱参照のために必要です。

SwiftでDelegateはどのように動作するか?

Swiftでのデリゲートの実装は3つのステップを含みます:プロトコルの宣言、所有者での弱いdelegateプロパティの作成、デリゲートクラスでのプロトコルの実装です。検証付きのカスタムUITextFieldの例を見てみましょう。

Swift
protocol ValidatorDelegate: AnyObject {
    func validate(_ input: String) -> Bool
    func validatorDidFail(_ input: String)
}

class ValidatedTextField: UITextField {
    weak var validator: ValidatorDelegate?
    
    override func textDidChange() {
        guard let text = self.text else { return }
        if validator?.validate(text) == false {
            validator?.validatorDidFail(text)
            self.layer.borderColor = UIColor.red.cgColor
        }
    }
}

class LoginViewController: UIViewController, ValidatorDelegate {
    let textField = ValidatedTextField()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.validator = self
    }
    
    func validate(_ input: String) -> Bool {
        return input.count >= 6
    }
    
    func validatorDidFail(_ input: String) {
        print("検証失敗:入力が短すぎます")
    }
}

LoginViewControllerはValidatorDelegateプロトコルを実装し、自身をtextFieldのデリゲートとして設定します。テキストが変更されるたびに、ValidatedTextFieldはvalidate(_:)を呼び出し、検証が失敗した場合はvalidatorDidFail(_:)を呼び出します。コントローラーはViewと検証ロジックの間の仲介役として機能します。

Delegate vs NotificationCenter vs Closure

デリゲート、通知、クロージャーの選択は、受信者の数とコンポーネントの結合度に依存します。各メカニズムはオブジェクト間の通信の問題を解決しますが、異なるトレードオフがあります。

特性DelegateNotificationCenterClosure
通信タイプ1:11:N1:1
結合度弱い(プロトコル経由)非常に弱い(文字列キー)中程度(コンテキストキャプチャ)
型安全性完全なし(Any?)完全
保持サイクルのリスクなし(weak)なしあり(selfキャプチャ)
使用する場面複数のメソッドを持つ複雑なコールバック多くの人が関心を持つイベント1-2のコールバックを持つ単純なクロージャー

Delegateは、関連する一連のイベントを単一の受信者に渡す必要がある場合に最適です。NotificationCenterはブロードキャスト通知に適しています。Closureは、URLSessionの完了ハンドラのような単純な非同期操作に使用します。

Objective-CでのDelegateの実装

Objective-Cはデリゲートを宣言するために@protocolと@optionalを使用します。Swiftとは異なり、すべてのプロトコルメソッドはデフォルトでオプショナルです。主な違いは、メソッドが実装されていない可能性があるため、デリゲートにメッセージを送信する前にrespondsToSelector:を呼び出すことです。

Objective-C
@protocol ImageCacheDelegate 
@optional
- (void)cacheDidStartDownload: (ImageCache *)cache;
- (void)cache: (ImageCache *)cache didCacheImage: (UIImage *)image;
@required
- (void)cache: (ImageCache *)cache didFailWithError: (NSError *)error;
@end

@interface ImageCache : NSObject
@property (nonatomic, weak) id<ImageCacheDelegate> delegate;
- (void)downloadImageAtURL: (NSURL *)url;
@end

@implementation ImageCache
- (void)downloadImageAtURL: (NSURL *)url {
    if ([self.delegate respondsToSelector:@selector(cacheDidStartDownload:)]) {
        [self.delegate cacheDidStartDownload:self];
    }
    // 非同期画像ローディング
}
@end

Objective-Cの主な違い:オプショナルメソッドを呼び出す前に、respondsToSelector:の確認が必要です。Swiftでは、オプショナルなプロトコルメソッドはこの確認を不要にします — オプショナルチェイニング(?.)が実装の欠如を自動的に処理します。

デリゲートを扱う際のよくある間違い

デリゲート使用の間違いは、メモリリーク、アプリのクラッシュ、わかりにくいバグにつながります。5つの最も一般的な問題を見てみましょう。

デリゲートへの強い参照

保持サイクルは最も一般的な間違いです。delegateプロパティがstrongとして宣言され、デリゲートが所有者オブジェクトを所有している場合、保持サイクルが形成されます。両方のオブジェクトはメモリから解放されることはありません。解決策:常にSwiftではweak var、Objective-Cでは@property (weak)としてデリゲートを宣言します。

dealloc後もデリゲートがnilにならない

所有者オブジェクトがデリゲートより長生きし、参照が残っている場合、デリゲートメソッドを呼び出すとEXC_BAD_ACCESSが発生します。弱参照はこの問題を自動的に解決します:デリゲートが解放された後、プロパティはnilになります。ただし、マルチスレッドシナリオでは、メインスレッドでデリゲートを追加で確認する必要があります。

プロトコル内のメソッドの過剰な数

20以上のメソッドを持つプロトコルは、インターフェース分離の原則(ISP)に違反します。UITableViewDelegateには約30のオプショナルメソッドがあります — これは歴史的な例外です。独自のプロトコルでは、責任をいくつかの小さなプロトコルに分割し、それぞれに独自の役割を持たせる方が良いでしょう。

iOSシステムAPIでのDelegateの例

AppleのシステムAPIはDelegateパターンを積極的に使用しています。すべてのiOSアプリケーションに登場するUIKitの3つの主要な例を見てみましょう。

APIプロトコル主要メソッド
UITableViewUITableViewDelegatedidSelectRowAt, heightForRowAt, willDisplay
UITextFieldUITextFieldDelegateshouldChangeCharactersIn, didBeginEditing, shouldReturn
URLSessionURLSessionDelegatedidReceiveChallenge, didCompleteWithError, didBecomeInvalidWithError

これらのプロトコルはそれぞれ異なる動作の側面を実装しています:UITableViewDelegateは外観とタッチ応答を管理し、UITextFieldDelegateはテキスト入力を制御し、URLSessionDelegateはネットワークイベントを処理します。これはパターンの柔軟性を示しています:デリゲートはあらゆる責任領域に適応できます。

よくある質問

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

Delegateは動作と外観を管理します(セルの高さ、タッチ応答)。DataSourceはデータを提供します(行数、セルの内容)。UITableViewDelegateとUITableViewDataSourceでは — これらはプレゼンテーションとデータの責任を分割する2つの別個のプロトコルです。

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

弱参照は保持サイクルを防ぎます。所有者(例:UITableView)はデリゲートへの参照をweakとしてのみ保持します。デリゲート(UIViewController)がテーブルを所有している場合、デリゲートへの強い参照はサイクルを生成します:ViewController → UITableView → Delegate(ViewController)。Weakはこのサイクルを断ち切ります。

SwiftUIでdelegateを使用できますか?

SwiftUIでは、Delegateパターンはあまり使用されません — 代わりに@Binding、@State、クロージャーが使用されます。ただし、デリゲートはUIViewRepresentableを通じたUIKit統合のために今でも使用されています。例えば、MKMapViewDelegateやWKUIDelegateは、UIKitコンポーネントをSwiftUIでラップする際に関連性を保っています。

Swiftプロトコルの@objc optionalとは何ですか?

@objc optionalは、Swiftプロトコルでオプショナルメソッドを宣言することを可能にします。これはObjective-Cランタイムとの互換性メカニズムです。@objcがない場合、すべてのSwiftプロトコルメソッドはデフォルトで必須です。Optionalは、デリゲートが必要なメソッドのみを実装できるUIKitプロトコルで使用されます。

1つのオブジェクトはいくつのデリゲートを持つことができますか?

1つのオブジェクトは、各delegateプロパティに対して1つのデリゲートのみを持つことができます。複数のオブジェクトに通知する必要がある場合は、マルチキャストデリゲート、デリゲートの配列、またはNotificationCenterを使用してください。Delegateパターンは元々1:1の関係として設計されています。

まとめ

  • Delegate — プロトコルを介してオブジェクトから別のオブジェクトへタスク実行を転送する動作デザインパターン
  • Swiftプロトコルはメソッドのセットを宣言します;オプショナルメソッドは@objc optionalでマークされ、必須メソッドは常に実装されます
  • 弱参照はデリゲートの保持サイクルとメモリリークを防ぐために必須です
  • UITableViewDelegateは最もよく知られた例です;そのメソッドはセルの高さ、選択、表示を管理します
  • Delegateは1:1対1:Nの関係と完全な型安全性においてNotificationCenterと異なります
  • Objective-CはオプショナルメソッドにrespondsToSelector:の確認が必要ですが、Swiftは自動的に処理します
  • 推奨:複数の関連メソッドを持つ複雑なコールバックにはdelegateを、単純なクロージャーにはclosureを使用してください

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

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

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

こちらもお読みください