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 — 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ć:
{ get } lub { get set }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.
Protocol deklaruje się słowem kluczowym protocol z nazwą i ciałem.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
Typ przyjmuje protokół przez dwukropek po nazwie:
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.
Property requirements określa się słowem kluczowym var i specyfikatorami dostępu { get } lub { get set }.
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.
Protocol może dziedziczyć inny protokół, dodając nowe wymagania. Tworzy to hierarchię kontraktów bez sztywnego powiązania z klasami.
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 — mechanizm pozwalający określić, że typ musi odpowiadać kilku protokołom jednocześnie, bez tworzenia nowego protokołu kombinowanego.
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 może być używany jako typ zmiennej, parametru funkcji lub elementu kolekcji. Jest to tak zwany typ egzystencjalny.
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.
Podczas pracy z protocol programiści często popełniają kilka powtarzających się błędów.
Drawable zamiast <T: Drawable> tam, gdzie potrzebny jest konkretny typAnyObject bez potrzeby, co wyklucza struct i enumCzęsto zadawane pytania
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.
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ść.
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.
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.
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
&) łączy protokoły bez dziedziczeniaany) i opaque types (some) — dwa sposoby pracy z protokołamiOpracujemy 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.
Przeczytaj również