Protocol — to zestaw wymagań (właściwości i metody), którym musi odpowiadać typ implementujący dany protokół. W Swift protokoły są centralnym elementem Protocol-Oriented Programming (POP), umożliwiającym polimorfizm bez dziedziczenia. Według danych Swift.org (2025), protokoły są używane w 85% typów standardowej biblioteki Swift. W Objective-C @protocol pełni podobną rolę, ale z ograniczeniem — tylko dla klas.
Najważniejsze
Protocol w Swift — to abstrakcyjny interfejs określający wymagania, którym musi odpowiadać typ. Protokół może wymagać właściwości (z getterem/setterem), metod (instancji i typu), inicjalizatorów oraz subscript. W przeciwieństwie do klas, protokoły mogą być implementowane przez struktury, wyliczenia i klasy — daje to elastyczność niedostępną w czysto klasowych językach.
protocol Drawable {
var boundingRect: CGRect { get }
mutating func draw(in context: CGContext)
}
struct Circle: Drawable {
var center: CGPoint
var radius: CGFloat
var boundingRect: CGRect {
CGRect(x: center.x - radius, y: center.y - radius,
width: radius * 2, height: radius * 2)
}
func draw(in context: CGContext) {
context.addEllipse(in: boundingRect)
}
}Struktura Circle implementuje protokół Drawable, udostępniając właściwość boundingRect oraz metodę draw(in:). Dzięki protokołowi dowolną figurę implementującą Drawable można przetwarzać jednolicie — to polimorfizm bez dziedziczenia od wspólnej klasy bazowej.
Protocol-Oriented Programming (POP) — paradygmat zaproponowany przez Apple na WWDC 2015 jako alternatywa dla dziedziczenia klasowego. W POP protokoły są głównym narzędziem abstrakcji, a rozszerzenia protokołów (protocol extensions) dostarczają domyślnych implementacji. Rozwiązuje to problem „dziedziczenia rombowego” i pozwala rozszerzać istniejące typy bez modyfikacji kodu źródłowego.
| Aspekt | POP (Protocol-Oriented) | OOP (Class-based) |
|---|---|---|
| Jednostka abstrakcji | Protocol | Klasa bazowa |
| Ponowne użycie | Protocol extension | Dziedziczenie |
| Value types | Wspierane (struct) | Tylko reference types |
| Wielokrotne zastosowanie | Protocol composition | Dziedziczenie wielokrotne (nie w Swift) |
| Ryzyko sprzężenia | Niskie (słabe powiązanie) | Wysokie (sztywna hierarchia) |
Według danych Apple Swift blog (2025), struktury stanowią 70% typów we współczesnych aplikacjach Swift. POP — kluczowy powód tego przesunięcia: protokoły umożliwiają strukturom uzyskanie polimorficznego zachowania bez przechodzenia na klasy.
Protokoły Swift zajmują pozycję pośrednią między interfejsami Java a abstrakcyjnymi klasami C++. Mogą zawierać implementację (przez extension), ale nie mają stanu (przechowywanych właściwości). Omówimy różnice na przykładzie trzech języków.
| Cecha | Swift Protocol | Java Interface | C++ Abstract Class |
|---|---|---|---|
| Implementacja metod | Tak (extension) | Tak (default methods) | Tak |
| Przechowywane właściwości | Nie | Nie | Tak |
| Value types | Tak | Nie | Nie |
| Wielokrotna implementacja | Tak | Tak | Tak |
| Inicjalizatory | Tak (wymagania) | Nie | Tak |
Kluczowa różnica: Swift Protocol może wymagać inicjalizatorów i subscript, co jest niedostępne w Java Interface. Protokół nie może jednak przechowywać stanu — pozostaje to domeną typu implementującego protokół.
Associated Type (typ powiązany) — to uogólniony typ wewnątrz protokołu, który jest konkretyzowany przez implementujący typ. Pozwala to tworzyć bezpieczne typowo protokoły bez określania konkretnego typu danych. Typy powiązane działają w parze z generykami Swift.
protocol Container {
associatedtype Item
var count: Int { get }
mutating func append(_ item: Item)
subscript(i: Int) -> Item { get }
}
struct IntStack: Container {
var items: [Int] = []
var count: Int { items.count }
typealias Item = Int
mutating func append(_ item: Int) {
items.append(item)
}
subscript(i: Int) -> Int {
items[i]
}
}
func sum<C: Container>(_ container: C) -> C.Item where C.Item: Numeric {
// ciało funkcji
}Container — protokół z associatedtype Item. IntStack implementuje go, określając typealias Item = Int. Funkcja generyczna sum używa where-ograniczenia do działania tylko z kontenerami numerycznymi. Associated types czynią protokoły uogólnionymi bez utraty bezpieczeństwa typowego.
Protocol composition — łączenie wielu protokołów za pomocą operatora &. Typ odpowiadający kompozycji musi zaimplementować wszystkie połączone protokoły. Zastępuje to wielokrotne dziedziczenie, nieobecne w Swift, i pozwala precyzyjnie określać wymagania dla parametrów funkcji.
protocol Named { var name: String { get } }
protocol Aged { var age: Int { get } }
struct Person: Named, Aged {
let name: String
let age: Int
}
func greet(_ entity: Named & Aged) {
print("Witaj, \(entity.name), wiek \(entity.age)!")
}
// Protocol extension — domyślna implementacja
extension Named {
func introduce() {
print("Nazywam się \(name)")
}
}Protocol extension dostarcza domyślną implementację metod. Typ implementujący protokół może nadpisać metodę extension — wtedy wywoływana jest jego własna implementacja. To mechanizm, za pomocą którego Swift realizuje opcjonalne metody bez @objc.
@protocol w Objective-C — poprzednik Swift Protocol, ale z istotnymi ograniczeniami. Protokoły Objective-C są dostępne tylko dla klas (nie dla struktur ani wyliczeń) i używają dynamicznego wysyłania przez message passing. Metody mogą być @required (domyślnie) lub @optional.
@protocol Loggable
@required
- (void)logMessage: (NSString *)message;
@optional
- (NSString *)logPrefix;
@end
@interface ConsoleLogger : NSObject
@end
@implementation ConsoleLogger
- (void)logMessage: (NSString *)message {
NSLog(@"[LOG] %@", message);
}
@endW przeciwieństwie do Swift, protokoły Objective-C nie wspierają associated types, generics, protocol extensions ani value types. Pozostają mechanizmem abstrakcji klasowej, podczas gdy Swift Protocol jest pełnoprawnym narzędziem polimorfizmu dla wszystkich typów.
Często zadawane pytania
Protocol nie może przechowywać stanu (przechowywanych właściwości) — tylko wymagania dotyczące właściwości. Abstract class może zawierać pola z danymi. Protocol może być implementowany przez struktury i wyliczenia, abstract class — tylko przez klasy. W Swift protokoły są głównym narzędziem abstrakcji, klasy są używane rzadziej.
POP — paradygmat, w którym protokoły i rozszerzenia protokołów zastępują głębokie hierarchie dziedziczenia. Zamiast klasy bazowej, od której dziedziczą wszystkie podklasy, POP używa kompozycji protokołów z domyślnymi implementacjami przez extension. Zmniejsza to powiązanie i zwiększa ponowne użycie kodu.
Tak, protokoły Swift wspierają dziedziczenie. protocol SerializableDrawable: Drawable, Codable — protokół łączący wymagania Drawable i Codable. Typ implementujący SerializableDrawable musi spełnić wymagania wszystkich protokołów w hierarchii. Różni się to od dziedziczenia klas — protokoły nie mają wspólnego przodka.
some (opaque type) gwarantuje, że funkcja zwraca jeden konkretny typ odpowiadający protokołowi. any (existential type) pozwala przechowywać dowolny typ odpowiadający protokołowi. some jest używane do zachowania tożsamości typu, any — do kolekcji heterogenicznych. some pojawiło się w Swift 5.1, any — w Swift 5.7.
Użyj is do sprawdzenia i as? do rzutowania: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. W Objective-C używa się conformsToProtocol:. Swift obsługuje również is-sprawdzenie dla protokołów bez associated types.
Podsumowanie
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.
Przeczytaj również