Protocol in Swift è un contratto che definisce un insieme di requisiti che qualsiasi tipo adottante deve soddisfare. I protocolli sono alla base della programmazione orientata ai protocolli (POP) — un paradigma raccomandato da Apple per Swift insieme alla classica OOP. Secondo la Apple Documentation, 2026, strutture, classi ed enum possono adottare protocolli, rendendo l’architettura flessibile e testabile.
Punti chiave
Protocol è un’interfaccia astratta che definisce ciò che un tipo deve essere in grado di fare, ma non come lo fa. In Swift, un protocollo è analogo alle interfacce in Java o Go, ma con capacità aggiuntive.
Un protocollo può richiedere:
{ get } o { get set }Secondo la WWDC 2015, Apple ha introdotto la programmazione orientata ai protocolli come approccio fondamentale per l’architettura delle applicazioni Swift. A differenza della OOP, dove l’ereditarietà delle classi crea gerarchie rigide, la POP offre la composizione di protocolli. Ciò offre flessibilità: un singolo tipo può conformarsi a più protocolli, ottenendo i loro requisiti e implementazioni tramite estensioni.
Protocol viene dichiarato con la parola chiave protocol, un nome e un corpo.
protocol Drawable {
func draw(context: CGContext)
var boundingBox: CGRect { get }
}
Un tipo adotta un protocollo usando due punti dopo il suo nome:
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)
}
}
Un singolo tipo può adottare più protocolli separati da virgole: struct MyType: ProtocolA, ProtocolB. Il compilatore verifica che tutti i requisiti di ciascun protocollo siano soddisfatti.
Requisiti di proprietà sono dichiarati con la parola chiave var e gli specificatori di accesso { get } o { get set }.
protocol UserProtocol {
var name: String { get }
var age: Int { get set }
static var maxAge: Int { get }
mutating func updateName(_ newName: String)
}
La parola chiave mutating in un protocollo indica che il metodo può modificare self. Le strutture devono implementare tale metodo come mutating, mentre le classi possono ometterlo. Requisiti di metodi sono dichiarati con una firma completa, incluse le etichette dei parametri.
Protocol può ereditare un altro protocollo, aggiungendo nuovi requisiti. Ciò crea una gerarchia di contratti senza un accoppiamento rigido alle classi.
protocol Vehicle {
var speed: Double { get set }
func move()
}
protocol Flyable: Vehicle {
var altitude: Double { get set }
func takeOff()
}
Un tipo che adotta Flyable deve soddisfare i requisiti di entrambi i protocolli — Vehicle e Flyable. Swift supporta l’ereditarietà multipla di protocolli: protocol A: B, C.
Protocol Composition è un meccanismo che permette di specificare che un tipo deve conformarsi a più protocolli simultaneamente, senza creare un nuovo protocollo combinato.
func render(_ item: Drawable & Animatable) {
item.draw(context: ...)
item.animate(duration: 0.3)
}
La composizione (&) funziona nei parametri di funzioni, variabili e vincoli generici. Il compilatore verifica che il tipo passato simultaneamente soddisfi tutti i protocolli. La composizione è ampiamente utilizzata in SwiftUI: some View è un generico con composizione.
Protocol Composition è preferibile alla creazione di una gerarchia di ereditarietà: invece di protocol A: B, C, si può adottare direttamente B & C. Ciò offre flessibilità e riduce l’accoppiamento. La composizione è particolarmente utile nei parametri di funzioni e vincoli generici dove è necessario combinare temporaneamente requisiti senza creare un protocollo intermedio. Ciò riduce il numero di tipi ausiliari nel codice.
Protocol può essere usato come tipo di una variabile, parametro di funzione o elemento di collezione. Questo è chiamato tipo esistenziale.
var drawableItem: Drawable
let items: [Drawable] = [Circle(...), Rectangle(...)]
func process(drawables: [any Drawable]) {
for item in drawables {
item.draw(context: ...)
}
}
La parola chiave any (Swift 5.6+) marca esplicitamente un esistenziale. Senza any, il compilatore emette un avviso. Swift supporta anche some (tipi opachi) per nascondere il tipo concreto dietro un protocollo — questo è un approccio standard in SwiftUI.
Quando si lavora con i protocolli, gli sviluppatori commettono spesso diversi errori ricorrenti.
Drawable invece di <T: Drawable> dove serve un tipo concretoAnyObject inutilmente, escludendo struct ed enumDomande frequenti
Protocol definisce solo requisiti senza implementazione (fino ai protocol extensions). Una classe astratta può contenere implementazione e stato. Swift non ha classi astratte — il loro ruolo è svolto dai protocolli con estensioni.
Sì, strutture, classi ed enum possono tutti adottare protocolli. Questa è la base della POP: non sei obbligato a usare classi per organizzare l’architettura. Le strutture con protocolli forniscono semantica di valore e immutabilità.
Tipo associato (associatedtype) è un segnaposto per un tipo che il tipo implementante determina da sé. Esempio: Collection ha associatedtype Element. È un generico a livello di protocollo.
Sì, aggiungi l’ereditarietà da AnyObject: protocol MyProtocol: AnyObject. Allora solo le classi potranno adottare questo protocollo. È utile per riferimenti deboli e delegati.
Usa is per verificare e as? per il casting: if let drawable = item as? Drawable. Funziona solo per protocolli senza tipi associati.
Riepilogo
&) combina protocolli senza ereditarietàany) e tipi opachi (some) — due modi per lavorare con i protocolliSvilupperemo 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