Protocol στη Swift — είναι μια σύμβαση που ορίζει ένα σύνολο απαιτήσεων που πρέπει να ικανοποιεί κάθε τύπος που το υιοθετεί. Τα πρωτόκολλα αποτελούν τη βάση του προσανατολισμένου σε πρωτόκολλα προγραμματισμού (POP) — ενός παραδείγματος που προτείνεται από την Apple για τη Swift παράλληλα με τον κλασικό OOP. Σύμφωνα με το Apple Documentation, 2026, οι δομές, οι κλάσεις και τα enum μπορούν να υιοθετούν πρωτόκολλα, καθιστώντας την αρχιτεκτονική ευέλικτη και ελέγξιμη.
Κύρια σημεία
Protocol — είναι μια αφηρημένη διεπαφή που ορίζει τι πρέπει να μπορεί να κάνει ένας τύπος, αλλά όχι πώς το κάνει. Στη Swift, το πρωτόκολλο είναι ανάλογο των διεπαφών από Java ή Go, αλλά με πρόσθετες δυνατότητες.
Ένα πρωτόκολλο μπορεί να απαιτεί:
{ get } ή { get set }Σύμφωνα με το WWDC 2015, η Apple παρουσίασε τον Protocol-Oriented Programming ως μια θεμελιώδη προσέγγιση στην αρχιτεκτονική εφαρμογών Swift. Σε αντίθεση με τον OOP, όπου η κληρονομικότητα κλάσεων δημιουργεί άκαμπτες ιεραρχίες, ο POP προτείνει σύνθεση πρωτοκόλλων. Αυτό παρέχει ευελιξία: ένας τύπος μπορεί να αντιστοιχεί σε πολλαπλά πρωτόκολλα, λαμβάνοντας τις απαιτήσεις και υλοποιήσεις τους μέσω extensions.
Protocol δηλώνεται με τη λέξη-κλειδί protocol με όνομα και σώμα.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
Ο τύπος υιοθετεί το πρωτόκολλο μέσω άνω-κάτω τελείας μετά το όνομα:
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. Ο μεταγλωττιστής ελέγχει αν πληρούνται όλες οι απαιτήσεις κάθε πρωτοκόλλου.
Property requirements καθορίζονται με τη λέξη-κλειδί var και προσδιοριστές πρόσβασης { get } ή { get set }.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
Η λέξη-κλειδί mutating σε ένα πρωτόκολλο σημαίνει ότι η μέθοδος μπορεί να τροποποιήσει το self. Οι δομές πρέπει να υλοποιούν μια τέτοια μέθοδο ως mutating, οι κλάσεις μπορούν να το παραλείψουν. Method requirements καθορίζονται με πλήρη υπογραφή συμπεριλαμβανομένων των ετικετών παραμέτρων.
Protocol μπορεί να κληρονομήσει ένα άλλο πρωτόκολλο, προσθέτοντας νέες απαιτήσεις. Αυτό δημιουργεί μια ιεραρχία συμβάσεων χωρίς άκαμπτη σύνδεση με κλάσεις.
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
Ο τύπος που υιοθετεί το Flyable πρέπει να ικανοποιεί τις απαιτήσεις και των δύο πρωτοκόλλων — τόσο του Vehicle όσο και του Flyable. Swift υποστηρίζει πολλαπλή κληρονομικότητα πρωτοκόλλων: protocol A: B, C.
Protocol Composition — ένας μηχανισμός που επιτρέπει τον καθορισμό ότι ένας τύπος πρέπει να αντιστοιχεί σε πολλαπλά πρωτόκολλα ταυτόχρονα, χωρίς τη δημιουργία νέου συνδυαστικού πρωτοκόλλου.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
Composition (&) λειτουργεί σε παραμέτρους συναρτήσεων, μεταβλητές και γενικούς περιορισμούς. Ο μεταγλωττιστής ελέγχει αν ο μεταβιβαζόμενος τύπος ταυτόχρονα ικανοποιεί όλα τα πρωτόκολλα. Το Composition χρησιμοποιείται συχνά στο SwiftUI: some View — είναι ένα generic με composition.
Το Protocol Composition είναι προτιμότερο από τη δημιουργία ιεραρχίας κληρονομικότητας: αντί για protocol A: B, C μπορεί να υιοθετηθεί άμεσα το B & C. Αυτό παρέχει ευελιξία και μειώνει τη σύζευξη. Το Composition είναι ιδιαίτερα βολικό σε παραμέτρους συναρτήσεων και γενικούς περιορισμούς, όπου χρειάζεται προσωρινός συνδυασμός απαιτήσεων χωρίς δημιουργία ενδιάμεσου πρωτοκόλλου. Αυτό μειώνει τον αριθμό βοηθητικών τύπων στον κώδικα.
Protocol μπορεί να χρησιμοποιηθεί ως τύπος μεταβλητής, παράμετρος συνάρτησης ή στοιχείο συλλογής. Αυτό ονομάζεται existential type.
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.
Κατά την εργασία με protocol, οι προγραμματιστές συχνά κάνουν αρκετά επαναλαμβανόμενα λάθη.
Drawable αντί για <T: Drawable> όπου χρειάζεται συγκεκριμένος τύποςAnyObject χωρίς ανάγκη, που αποκλείει struct και enumΣυχνές ερωτήσεις
Protocol ορίζει μόνο απαιτήσεις χωρίς υλοποίηση (μέχρι τα protocol extensions). Το abstract class μπορεί να περιέχει υλοποίηση και κατάσταση. Στη Swift δεν υπάρχουν αφηρημένες κλάσεις — τον ρόλο τους παίζουν τα πρωτόκολλα με extensions.
Ναι, οι δομές, οι κλάσεις και τα enum — όλα μπορούν να υιοθετούν πρωτόκολλα. Αυτή είναι η βάση του POP: δεν είστε υποχρεωμένοι να χρησιμοποιείτε κλάσεις για την οργάνωση της αρχιτεκτονικής. Οι δομές με πρωτόκολλα παρέχουν σημασιολογία τιμής και αμεταβλητότητα.
Associated type (associatedtype) — ένα placeholder για τον τύπο που ο υλοποιών τύπος καθορίζει μόνος του. Παράδειγμα: το Collection έχει associatedtype Element. Αυτό είναι generic σε επίπεδο πρωτοκόλλου.
Ναι, προσθέστε κληρονομικότητα από το AnyObject: protocol MyProtocol: AnyObject. Τότε μόνο κλάσεις μπορούν να υιοθετήσουν αυτό το πρωτόκολλο. Αυτό είναι χρήσιμο για weak αναφορές και delegates.
Χρησιμοποιήστε το is για έλεγχο και το as? για μετατροπή: if let drawable = item as? Drawable. Αυτό λειτουργεί μόνο για πρωτόκολλα χωρίς associated types.
Σύνοψη
&) συνδυάζει πρωτόκολλα χωρίς κληρονομικότηταany) και opaque types (some) — δύο τρόποι εργασίας με πρωτόκολλαΘα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης