Protocol è un insieme di requisiti (proprietà e metodi) che un tipo che adotta il protocollo deve soddisfare. In Swift, i protocolli sono l'elemento centrale della Protocol-Oriented Programming (POP), che consente il polimorfismo senza ereditarietà. Secondo Swift.org (2025), i protocolli sono utilizzati nell'85% dei tipi della libreria standard Swift. In Objective-C, @protocol svolge un ruolo simile, ma con una limitazione — solo per le classi.
Punti chiave
Protocol in Swift è un'interfaccia astratta che definisce i requisiti che un tipo deve soddisfare. Un protocollo può richiedere proprietà (con getter/setter), metodi (di istanza e di tipo), inizializzatori e subscript. A differenza delle classi, i protocolli possono essere adottati da strutture, enumerazioni e classi — offrendo flessibilità non disponibile nei linguaggi puramente basati su classi.
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)
}
}La struttura Circle adotta il protocollo Drawable, fornendo la proprietà boundingRect e il metodo draw(in:). Grazie al protocollo, qualsiasi forma che implementa Drawable può essere gestita in modo uniforme — questo è polimorfismo senza ereditare da una classe base comune.
Protocol-Oriented Programming (POP) è un paradigma introdotto da Apple al WWDC 2015 come alternativa all'ereditarietà basata su classi. In POP, i protocolli sono lo strumento di astrazione principale e le estensioni di protocollo forniscono implementazioni predefinite. Ciò risolve il problema dell'«ereditarietà a diamante» e consente di estendere i tipi esistenti senza modificare il codice sorgente.
| Aspetto | POP (Orientato ai Protocolli) | OOP (Basato su Classi) |
|---|---|---|
| Unità di astrazione | Protocol | Classe base |
| Meccanismo di riutilizzo | Protocol extension | Ereditarietà |
| Value types | Supportati (struct) | Solo reference types |
| Adozione multipla | Protocol composition | Ereditarietà multipla (non in Swift) |
| Rischio di accoppiamento | Basso (accoppiamento debole) | Alto (gerarchia rigida) |
Secondo il blog Apple Swift (2025), le strutture rappresentano il 70% dei tipi nelle applicazioni Swift moderne. POP è una ragione chiave di questo cambiamento: i protocolli consentono alle strutture di ottenere un comportamento polimorfico senza passare alle classi.
I protocolli Swift occupano una posizione intermedia tra le interfacce Java e le classi astratte C++. Possono contenere implementazioni (tramite estensioni) ma non possono avere stato (proprietà memorizzate). Esaminiamo le differenze tra tre linguaggi.
| Caratteristica | Swift Protocol | Java Interface | C++ Abstract Class |
|---|---|---|---|
| Implementazione metodi | Sì (extension) | Sì (default methods) | Sì |
| Proprietà memorizzate | No | No | Sì |
| Value types | Sì | No | No |
| Implementazione multipla | Sì | Sì | Sì |
| Inizializzatori | Sì (requisiti) | No | Sì |
Differenza chiave: Swift Protocol può richiedere inizializzatori e subscript, cosa non disponibile in Java Interface. Tuttavia, un protocollo non può memorizzare stato — questo rimane responsabilità del tipo che adotta il protocollo.
Associated Type (tipo associato) è un tipo generico all'interno di un protocollo che viene concretizzato dal tipo che lo adotta. Ciò consente di creare protocolli type-safe senza specificare un tipo di dati concreto. I tipi associati lavorano in tandem con i generics 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 {
// corpo della funzione
}Container è un protocollo con associatedtype Item. IntStack lo implementa specificando typealias Item = Int. La funzione generica sum utilizza una clausola where per lavorare solo con contenitori numerici. I tipi associati rendono i protocolli generici senza perdere la sicurezza di tipo.
Protocol composition — combinazione di più protocolli tramite l'operatore &. Un tipo conforme a una composizione deve implementare tutti i protocolli combinati. Ciò sostituisce l'ereditarietà multipla, assente in Swift, e consente di specificare con precisione i requisiti dei parametri di funzione.
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("Ciao, \(entity.name), età \(entity.age)!")
}
// Protocol extension — implementazione predefinita
extension Named {
func introduce() {
print("Mi chiamo \(name)")
}
}Protocol extension fornisce implementazioni di metodi predefiniti. Un tipo che adotta il protocollo può sovrascrivere il metodo dell'estensione — in tal caso, viene chiamata la sua implementazione. Questo è il meccanismo con cui Swift implementa metodi opzionali senza @objc.
@protocol in Objective-C è il predecessore di Swift Protocol, ma con limitazioni significative. I protocolli Objective-C sono disponibili solo per le classi (non per strutture o enumerazioni) e utilizzano dispatch dinamico tramite message passing. I metodi possono essere @required (predefinito) o @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);
}
@endA differenza di Swift, i protocolli Objective-C non supportano tipi associati, generics, estensioni di protocollo o value types. Rimangono un meccanismo di astrazione basato su classi, mentre Swift Protocol è uno strumento di polimorfismo completo per tutti i tipi.
Domande frequenti
Protocol non può memorizzare stato (proprietà memorizzate) — solo requisiti di proprietà. Una classe astratta può contenere campi dati. Un protocollo può essere adottato da strutture ed enumerazioni, mentre una classe astratta può essere solo sottoclassata da classi. In Swift, i protocolli sono lo strumento di astrazione principale; le classi sono usate meno frequentemente.
POP è un paradigma dove protocolli ed estensioni di protocollo sostituiscono gerarchie di ereditarietà profonde. Invece di una classe base da cui tutte le sottoclassi ereditano, POP utilizza la composizione di protocolli con implementazioni predefinite tramite estensione. Ciò riduce l'accoppiamento e migliora la riutilizzabilità del codice.
Sì, i protocolli Swift supportano l'ereditarietà. protocol SerializableDrawable: Drawable, Codable — un protocollo che combina i requisiti di Drawable e Codable. Un tipo che adotta SerializableDrawable deve soddisfare i requisiti di tutti i protocolli nella gerarchia. Ciò differisce dall'ereditarietà di classe — i protocolli non hanno un antenato comune.
some (tipo opaco) garantisce che una funzione restituisca un tipo specifico conforme al protocollo. any (tipo esistenziale) consente di memorizzare qualsiasi tipo conforme al protocollo. some è usato per preservare l'identità del tipo, any — per collezioni eterogenee. some è apparso in Swift 5.1, any — in Swift 5.7.
Usa is per verificare e as? per il casting: if let drawable = object as? Drawable { drawable.draw(in: ctx) }. In Objective-C si usa conformsToProtocol:. Swift supporta anche la verifica is per protocolli senza tipi associati.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche