Protocol w Swift — co to jest, składnia i możliwości

Autor: IT Sectr Opublikowano: 2026-06-17 Czas czytania: 6 min

Protocol w Swift — to kontrakt definiujący zestaw wymagań, którym musi sprostać każdy typ, który go przyjmuje. Protokoły leżą u podstaw programowania zorientowanego na protokoły (POP) — paradygmatu zalecanego przez Apple dla Swift obok klasycznego OOP. Według Apple Documentation, 2026, struktury, klasy i enum mogą przyjmować protokoły, co czyni architekturę elastyczną i testowalną.

Najważniejsze

  • Protocol — kontrakt z wymaganiami dla struktur, klas i enum
  • Requirements obejmują metody, właściwości, inicjalizatory i subskrypty
  • Protocol Composition pozwala łączyć wiele protokołów
  • POP — programowanie zorientowane na protokoły, alternatywa dla dziedziczenia
  • Protocol Extensions dodają domyślne implementacje metod

Czym jest Protocol w Swift?

Protocol — to abstrakcyjny interfejs określający, co typ powinien umieć, ale nie jak to robi. W Swift protokół jest odpowiednikiem interfejsów z Java lub Go, ale z dodatkowymi możliwościami.

Protokół może wymagać:

  • Metody instancji i typu (statyczne)
  • Właściwości z oznaczeniem { get } lub { get set }
  • Inicjalizatory
  • Subskrypty
  • Associated types (generyki na poziomie protokołu)

Według WWDC 2015, Apple przedstawiło Protocol-Oriented Programming jako fundamentalne podejście do architektury aplikacji Swift. W przeciwieństwie do OOP, gdzie dziedziczenie klas tworzy sztywne hierarchie, POP proponuje kompozycję protokołów. Daje to elastyczność: jeden typ może odpowiadać wielu protokołom, otrzymując ich wymagania i implementacje poprzez extensions.

Składnia deklaracji protokołów

Protocol deklaruje się słowem kluczowym protocol z nazwą i ciałem.

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

Typ przyjmuje protokół przez dwukropek po nazwie:

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)
    }
}

Jeden typ może przyjąć wiele protokołów oddzielonych przecinkami: struct MyType: ProtocolA, ProtocolB. Kompilator sprawdza, czy wszystkie wymagania każdego protokołu zostały spełnione.

Wymagania metod i właściwości

Property requirements określa się słowem kluczowym var i specyfikatorami dostępu { get } lub { get set }.

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

Słowo kluczowe mutating w protokole oznacza, że metoda może modyfikować self. Struktury muszą zaimplementować taką metodę jako mutating, klasy mogą to pominąć. Method requirements określa się z pełną sygnaturą, łącznie z etykietami parametrów.

Dziedziczenie protokołów

Protocol może dziedziczyć inny protokół, dodając nowe wymagania. Tworzy to hierarchię kontraktów bez sztywnego powiązania z klasami.

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

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

Typ przyjmujący Flyable musi spełnić wymagania obu protokołów — zarówno Vehicle, jak i Flyable. Swift obsługuje wielokrotne dziedziczenie protokołów: protocol A: B, C.

Protocol Composition

Protocol Composition — mechanizm pozwalający określić, że typ musi odpowiadać kilku protokołom jednocześnie, bez tworzenia nowego protokołu kombinowanego.

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

Composition (&) działa w parametrach funkcji, zmiennych i ograniczeniach generycznych. Kompilator sprawdza, czy przekazany typ jednocześnie spełnia wszystkie protokoły. Composition jest często używane w SwiftUI: some View — to generic z composition.

Protocol Composition jest preferowany zamiast tworzenia hierarchii dziedziczenia: zamiast protocol A: B, C można przyjąć B & C bezpośrednio. Daje to elastyczność i zmniejsza powiązania. Composition jest szczególnie wygodny w parametrach funkcji i ograniczeniach generycznych, gdzie trzeba tymczasowo połączyć wymagania bez tworzenia pośredniego protokołu. Zmniejsza to liczbę typów pomocniczych w kodzie.

Protocol jako typ

Protocol może być używany jako typ zmiennej, parametru funkcji lub elementu kolekcji. Jest to tak zwany typ egzystencjalny.

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

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

Słowo kluczowe any (Swift 5.6+) wyraźnie wskazuje na typ egzystencjalny. Bez any kompilator wyświetla ostrzeżenie. Swift obsługuje również some (opaque types) do ukrywania konkretnego typu za protokołem — to standardowa technika w SwiftUI.

Typowe błędy z protokołami

Podczas pracy z protocol programiści często popełniają kilka powtarzających się błędów.

  • Zapomniane mutating — metoda w protokole oznaczona jako mutating, a struktura implementuje ją bez słowa kluczowego
  • Protocol as type zamiast generic — użycie Drawable zamiast <T: Drawable> tam, gdzie potrzebny jest konkretny typ
  • Circular protocol reference — protokół odwołujący się do siebie przez associated type, bez poprawnego rozwiązania
  • Class-only protocol — użycie AnyObject bez potrzeby, co wyklucza struct i enum

Często zadawane pytania

Czym różni się protocol od abstract class?

Protocol określa tylko wymagania bez implementacji (do momentu protocol extensions). Abstract class może zawierać implementację i stan. W Swift nie ma klas abstrakcyjnych — ich rolę pełnią protokoły z extensions.

Czy struct może przyjąć protocol?

Tak, struktury, klasy i enum — wszystkie mogą przyjmować protokoły. To podstawa POP: nie musisz używać klas do organizacji architektury. Struktury z protokołami zapewniają semantykę wartości i niezmienność.

Czym jest associated type w protokole?

Associated type (associatedtype) — placeholder dla typu, który typ implementujący określa samodzielnie. Przykład: Collection ma associatedtype Element. To generic na poziomie protokołu.

Czy można ograniczyć protokół tylko dla klas?

Tak, dodaj dziedziczenie od AnyObject: protocol MyProtocol: AnyObject. Wtedy tylko klasy będą mogły przyjąć ten protokół. Jest to przydatne dla weak-odsyłaczy i delegatów.

Jak sprawdzić zgodność z protokołem w runtime?

Użyj is do sprawdzenia i as? do rzutowania: if let drawable = item as? Drawable. Działa to tylko dla protokołów bez associated types.

Podsumowanie

  • Protocol — kontrakt dla metod, właściwości, inicjalizatorów i subskryptów
  • Class, struct, enum — wszystkie typy mogą przyjmować protokoły
  • Dziedziczenie protokołów tworzy hierarchię kontraktów bez sztywnego powiązania
  • Protocol Composition (&) łączy protokoły bez dziedziczenia
  • Existential types (any) i opaque types (some) — dwa sposoby pracy z protokołami
  • POP zalecany przez Apple jako alternatywa dla klasycznego dziedziczenia klas
  • Protocol Extensions pozwalają dodawać domyślne implementacje

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również