SwiftのProtocol — その概要、構文、可能性

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

Protocol in Swiftは、採用する型が満たさなければならない一連の要件を定義する契約です。プロトコルは、プロトコル指向プログラミング(POP)の基礎です — AppleがSwiftのために従来のOOPと並んで推奨するパラダイムです。Apple Documentation, 2026によると、構造体、クラス、列挙型はプロトコルを採用でき、アーキテクチャを柔軟でテスト可能にします。

重要なポイント

  • Protocol — 構造体、クラス、列挙型のための要件を備えた契約
  • 要件にはメソッド、プロパティ、イニシャライザ、サブスクリプトが含まれる
  • Protocol Compositionにより複数のプロトコルを組み合わせられる
  • POP — 継承に代わるプロトコル指向プログラミング
  • Protocol Extensionsはメソッドにデフォルト実装を追加する

SwiftにおけるProtocolとは?

Protocolは、型が何をできるべきかを定義する抽象インターフェースであり、どのようにそれを行うかは定義しません。Swiftでは、プロトコルはJavaやGoのインターフェースに類似していますが、追加の機能を備えています。

プロトコルは以下を要求できます:

  • インスタンスメソッドと型メソッド(静的)
  • プロパティ{ get }または{ get set }指定子付き)
  • イニシャライザ
  • サブスクリプト
  • associated types(プロトコルレベルのジェネリクス)

WWDC 2015によると、Appleはプロトコル指向プログラミングをSwiftアプリケーションアーキテクチャの基本的なアプローチとして導入しました。クラスの継承が堅い階層構造を作るOOPとは異なり、POPはプロトコルの合成を提供します。これにより柔軟性が生まれます:単一の型が複数のプロトコルに準拠でき、拡張を通じてそれらの要件と実装を獲得できます。

プロトコル宣言の構文

Protocolはキーワードprotocol、名前、本体で宣言されます。

swift
protocol Drawable {
    func draw(context: CGContext)
    var boundingBox: CGRect { get }
}

型は名前の後にコロンを使用してプロトコルを採用します:

swift
struct Circle: Drawable {
    let center: CGPoint
    let radius: CGFloat

    func draw(context: CGContext) {
        context.addArc(center: center, radius: radius, ...)
    }

    var boundingBox: CGRect {
        CGRect(x: center.x - radius, y: center.y - radius,
               width: radius * 2, height: radius * 2)
    }
}

単一の型はカンマ区切りで複数のプロトコルを採用できます:struct MyType: ProtocolA, ProtocolB。コンパイラは各プロトコルのすべての要件が満たされているか検証します。

プロパティとメソッドの要件

プロパティ要件はキーワードvarとアクセス指定子{ get }または{ get set }で宣言されます。

swift
protocol UserProtocol {
    var name: String { get }
    var age: Int { get set }
    static var maxAge: Int { get }
    mutating func updateName(_ newName: String)
}

プロトコル内のキーワードmutatingは、メソッドがselfを変更できることを示します。構造体はそのようなメソッドをmutatingとして実装する必要がありますが、クラスは省略できます。メソッド要件はパラメータラベルを含む完全なシグネチャで宣言されます。

プロトコルの継承

Protocolは別のプロトコルを継承でき、新しい要件を追加できます。これにより、クラスへの堅い結合なしに契約の階層構造が作成されます。

swift
protocol Vehicle {
    var speed: Double { get set }
    func move()
}

protocol Flyable: Vehicle {
    var altitude: Double { get set }
    func takeOff()
}

Flyableを採用する型は、両方のプロトコル — VehicleFlyable — の要件を満たさなければなりません。Swiftはプロトコルの多重継承をサポートしています:protocol A: B, C

Protocol Composition

Protocol Compositionは、新しい結合プロトコルを作成せずに、型が同時に複数のプロトコルに準拠する必要があることを指定できるメカニズムです。

swift
func render(_ item: Drawable & Animatable) {
    item.draw(context: ...)
    item.animate(duration: 0.3)
}

合成(&)は関数パラメータ、変数、ジェネリック制約で機能します。コンパイラは渡された型が同時にすべてのプロトコルを満たすか検証します。合成はSwiftUIで広く使用されています:some Viewは合成を伴うジェネリクスです。

Protocol Compositionは継承階層を作成するよりも望ましいです:protocol A: B, Cの代わりに、直接B & Cを採用できます。これにより柔軟性が向上し、結合が減少します。合成は特に、中間プロトコルを作成せずに一時的に要件を組み合わせる必要がある関数パラメータやジェネリック制約で役立ちます。これによりコード内の補助型の数が減ります。

型としてのプロトコル

Protocolは変数、関数パラメータ、コレクション要素の型として使用できます。これは existential type と呼ばれます。

swift
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]

func process(drawables: [any Drawable]) {
    for item in drawables {
        item.draw(context: ...)
    }
}

キーワードany(Swift 5.6+)は明示的に existential を示します。anyがない場合、コンパイラは警告を発します。Swiftはプロトコルの背後に具体的な型を隠すためのsome(opaque types)もサポートしています — これはSwiftUIでの標準的なアプローチです。

プロトコルでよくある間違い

プロトコルを扱う際、開発者はしばしばいくつかの繰り返し発生する間違いを犯します。

  • mutatingの忘れ — プロトコルでメソッドがmutatingとマークされているが、構造体がキーワードなしで実装する
  • ジェネリクスの代わりにプロトコルを型として使用 — 具体的な型が必要な場所で<T: Drawable>の代わりにDrawableを使用する
  • 循環プロトコル参照 — 適切な解決なしにassociated typeを通じて自分自身を参照するプロトコル
  • クラス専用プロトコル — 不必要にAnyObjectを使用し、構造体と列挙型を除外する

よくある質問

プロトコルと抽象クラスの違いは?

Protocolは実装なしで要件のみを定義します(protocol extensionsの登場まで)。抽象クラスは実装と状態を含むことができます。Swiftには抽象クラスはありません — その役割は拡張を伴うプロトコルが果たします。

構造体はプロトコルを採用できますか?

はい、構造体、クラス、列挙型はすべてプロトコルを採用できます。これがPOPの基礎です:アーキテクチャを組織化するためにクラスを使う必要はありません。プロトコルを持つ構造体は値セマンティクスと不変性を提供します。

プロトコルのassociated typeとは?

Associated typeassociatedtype)は、実装する型が自分で決定する型のプレースホルダーです。例:Collectionにはassociatedtype Elementがあります。これはプロトコルレベルのジェネリクスです。

プロトコルをクラスだけに制限できますか?

はいAnyObjectからの継承を追加します:protocol MyProtocol: AnyObject。そうするとクラスのみがこのプロトコルを採用できます。これは弱参照やデリゲートに便利です。

実行時にプロトコル準拠を確認するには?

確認にはisを、キャストにはas?を使用します:if let drawable = item as? Drawable。これはassociated typeのないプロトコルでのみ機能します。

まとめ

  • Protocol — メソッド、プロパティ、イニシャライザ、サブスクリプトのための契約
  • Class, struct, enum — すべての型がプロトコルを採用可能
  • 継承は堅い結合なしに契約の階層構造を作る
  • Protocol Composition&)は継承なしでプロトコルを組み合わせる
  • Existential typesany)とopaque typessome) — プロトコルを扱う2つの方法
  • POPはAppleが従来のクラス継承の代替として推奨
  • Protocol Extensionsでデフォルト実装を追加可能

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

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

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

こちらもお読みください