Die Protokollzusammensetzung ist ein Mechanismus in Swift, der es ermöglicht, einen Typ zu erstellen, der mehrere Protokolle gleichzeitig erfüllen muss. Dies ist ein alternativer Weg, um die mehrfache Vererbung zu ersetzen, die es in Swift für Klassen nicht gibt.
Hintergrund
Objective-C unterstützte die mehrfache Vererbung nur für Protokolle, nicht für Klassen. Swift setzt diese Tradition fort und legt den Fokus auf Protokolle und deren Kombination zur Erstellung neuer Abstraktionen.
Problem
Programme haben oft die Aufgabe, einen Typ zu erstellen, dessen Verhalten durch mehrere Abstraktionen bestimmt wird. Die mehrfache Vererbung führt unvermeidlich zu Konflikten in Hierarchien; in Swift wird dies sicher durch Protokolle und Protokollzusammensetzung gelöst.
Lösung
In Swift können Protokolle mit dem Operator '&' kombiniert werden. Dies ermöglicht es, Variablen oder Funktion Parameter zu erstellen, die mehreren Protokollen gleichzeitig entsprechen müssen.
Beispielcode:
protocol Drivable { func drive() } protocol Flyable { func fly() } struct FlyingCar: Drivable, Flyable { func drive() { print("Driving") } func fly() { print("Flying") } } func testVehicle(_ vehicle: Drivable & Flyable) { vehicle.drive() vehicle.fly() } testVehicle(FlyingCar())
Wichtige Merkmale:
Kann man ein Objekt, das nur eines der Protokolle implementiert, als Parameter in die Protokollzusammensetzung übergeben?
Nein, das Objekt muss alle Protokolle implementieren, die an der Zusammensetzung beteiligt sind, andernfalls gibt der Compiler einen Fehler aus.
Beispielcode:
// struct Car: Drivable {} — kann nicht an testVehicle übergeben werden, da fly() nicht implementiert ist
Funktioniert die Protokollzusammensetzung auch mit Typen und nicht nur mit Werten?
Die Protokollzusammensetzung wird auf Werte (Variablen, Funktionsparameter) angewendet, aber nicht bei der Typdefinition eines Objekts verwendet (z. B. kann man einen neuen Typ nicht als eine "Zusammensetzung" von Protokollen deklarieren — nur die Variable).
Beispielcode:
var obj: SomeProtocol & AnotherProtocol // zulässig // typealias MyType = SomeClass & AnotherProtocol // Fehler
Kann man Klassen und Protokolle mit '&' kombinieren?
Ja, aber mit einer Einschränkung: Nur ein Klassen Typ (Klasse oder deren Abkömmling) kann links stehen, alle anderen müssen Protokolle sein; anderenfalls gibt der Compiler einen Fehler aus.
Beispielcode:
class A {} protocol B {} // func f(obj: A & B) {} // zulässig // func f(obj: A & AnotherClass & B) {} // Fehler! Nur ein Klassen Typ ist erlaubt
In einem Projekt werden Objekte mit Protokollzusammensetzung verwendet, um Daten zwischen Schichten zu übertragen, obwohl ein Protokoll ausreichend gewesen wäre:
func present(item: Displayable & Serializable) { ... }
Vorteile:
Verwendung der Protokollzusammensetzung nur in klaren Fällen — zum Beispiel bei der Verarbeitung von Objekten, die gleichzeitig Codable und Identifiable für die generische Serialisierung unterstützen:
func save<T: Codable & Identifiable>(_ item: T) { ... }
Vorteile: