Sendable — cos'è, protocollo di sicurezza dei thread

Autore: IT Sectr Pubblicato: 2026-06-18 Tempo di lettura: 10 min

Sendable è un protocollo Swift che contrassegna i tipi sicuri per il trasferimento tra thread. Quando si lavora con la concorrenza (actor, async/await, Task), il compilatore Swift richiede che tutti i dati trasferiti tra contesti isolati siano conformi a Sendable. Ciò impedisce il trasferimento accidentale di tipi non sicuri che potrebbero portare a race condition. Il protocollo funge da contratto: un tipo conforme a Sendable garantisce l'assenza di stato interno non sincronizzato. Secondo WWDC 2021, il protocollo Sendable è un elemento obbligatorio nella progettazione di un'architettura multithread sicura.

Punti chiave

  • Sendable — un protocollo che garantisce l'assenza di race condition nel trasferimento tra thread
  • Tipi valore (struct, enum) sono automaticamente conformi a Sendable se tutte le loro proprietà sono Sendable
  • @unchecked Sendable — un meccanismo di bypass per le classi di cui lo sviluppatore si assume la responsabilità della sicurezza
  • Closure Sendable sono contrassegnate con l'attributo @Sendable, che verifica la cattura delle variabili
  • Il compilatore genera un errore se un tipo non Sendable viene trasferito tra contesti isolati

Cos'è il protocollo Sendable in Swift?

Sendable è un protocollo della libreria standard Swift (SE-0302) che contrassegna i tipi sicuri per il trasferimento tra domini di isolamento. Un dominio di isolamento significa un actor, un'attività Task o un contesto @MainActor. Sendable non contiene requisiti — funge da marcatore di sicurezza.

Perché Sendable è necessario

Prima di Swift 5.5, gli sviluppatori potevano trasferire qualsiasi oggetto tra thread tramite DispatchQueue e il compilatore non verificava se fosse sicuro. Sendable colma questa lacuna: ora il compilatore stesso traccia i trasferimenti tra thread e blocca quelli non sicuri. Ciò rende il codice concorrente più affidabile ancora prima dell'esecuzione.

swift
struct UserProfile: Sendable {
    let name: String
    let age: Int
}

class NonSendableClass {
    var counter: Int = 0
}

Nell'esempio, UserProfile può essere trasferito in sicurezza tra thread perché è una struct con proprietà costanti di tipi Sendable. NonSendableClass causerà un errore di compilazione quando si tenta di trasferirlo tramite await o in una Task.

Quali tipi sono conformi a Sendable per impostazione predefinita

I tipi Sendable in Swift si dividono in tre categorie: tipi valore con proprietà Sendable, classi finali con stato immutabile e funzioni/closure contrassegnate con @Sendable. Il compilatore deduce automaticamente la conformità Sendable per i tipi valore.

Tipi valore e conformità automatica

Struct, Enum e tupla diventano automaticamente Sendable se tutte le loro proprietà e valori associati sono anch'essi Sendable. Questo è un approccio conservativo: se almeno una proprietà non è conforme a Sendable, l'intero tipo non sarà riconosciuto come sicuro.

TipoSendableCondizione
StructSì (senza dichiarazione esplicita)Tutte le proprietà sono Sendable
EnumSì (senza dichiarazione esplicita)Tutti i valori associati sono Sendable
Final classSì (con dichiarazione esplicita)Tutte le proprietà let sono Sendable, nessun var
Non-final classNoNon può essere Sendable a causa dell'ereditarietà

Tipi di base

Tutti i tipi incorporati di Swift — Int, String, Double, Bool, Optional, Array, Dictionary, Set — sono conformi a Sendable. Ciò rende la composizione dei tipi sicura per impostazione predefinita. Lo sviluppatore deve solo prestare attenzione alle classi personalizzate.

Sendable e classi: @unchecked Sendable

@unchecked Sendable è un meccanismo che consente a una classe di dichiararsi esplicitamente come Sendable, bypassando i controlli del compilatore. Lo sviluppatore si assume la responsabilità della sicurezza dei thread di tale classe. Ciò è utile per i bridge Objective-C e le strutture ottimizzate.

Quando usare @unchecked Sendable

@unchecked Sendable viene utilizzato quando una classe garantisce internamente la sicurezza tramite lock o operazioni atomiche, ma il compilatore non può verificarlo staticamente. Ad esempio, una classe con os_unfair_lock o pthread_mutex_t — la sua sicurezza dei thread è garantita dal codice, ma Swift non lo vede.

swift
final class AtomicCounter: @unchecked Sendable {
    private var value: Int = 0
    private let lock = NSLock()
    
    func increment() {
        lock.lock()
        value += 1
        lock.unlock()
    }
}

L'uso di @unchecked Sendable deve essere fatto con cautela. È un segnale esplicito per altri sviluppatori: «ho verificato, è sicuro». Un errore nell'implementazione può portare a race condition difficili da individuare. Prima di usare @unchecked, assicurati che il tipo non possa davvero essere riscritto come tipo valore.

Sendable in combinazione con Actor

Actor e Sendable sono due facce della stessa medaglia. Actor isola il suo stato, ma per scambiare dati con il mondo esterno deve restituire tipi Sendable. Se un metodo di actor restituisce un tipo non Sendable, il compilatore emette un avviso o un errore.

Trasferimento di dati tramite Sendable

Quando un actor invia dati a codice esterno, questi dati attraversano il confine di isolamento. Sendable garantisce che il destinatario possa usarli in sicurezza al di fuori dell'actor. L'actor rimane isolato — il suo stato interno non viene esposto.

swift
struct AccountSnapshot: Sendable {
    let id: UUID
    let balance: Double
    let lastUpdated: Date
}

actor BankActor {
    private var balance: Double = 0
    
    func snapshot() async -> AccountSnapshot {
        return AccountSnapshot(
            id: UUID(),
            balance: balance,
            lastUpdated: Date()
        )
    }
}

AccountSnapshot è una struct Sendable che contiene solo proprietà let di tipi Sendable. Questo approccio è una best practice per estrarre dati da un actor. Lo snapshot dello stato viene trasferito per valore e l'actor non perde il controllo del suo stato.

Funzioni e closure Sendable

@Sendable è un attributo per funzioni e closure che garantisce che la closure non catturi dati non Sendable in modo mutabile. Quando una closure viene trasferita a una Task o a un metodo di actor, deve essere Sendable.

Controllo della cattura nelle closure @Sendable

Il compilatore verifica che la closure @Sendable non catturi riferimenti mutabili a classi. La cattura di proprietà let di tipi Sendable è consentita. La cattura di una variabile var di un tipo riferimento causerà un errore perché la closure potrebbe essere eseguita simultaneamente alla mutazione.

swift
func performAsync(operation: @Sendable () -> Void) {
    Task {
        await operation()
    }
}

let constant = "Safe"
var counter = 0
// counter — catturare var muta counter, errore di compilazione
performAsync { // ❌ Mutazione della variabile catturata
    print(constant)
}

La regola è semplice: una closure @Sendable può catturare solo dati che sono essi stessi Sendable e che non verranno mutati dall'esterno. Per le classi, è consentita la cattura di un riferimento debole weak self se la classe non è contrassegnata come Sendable. Ciò previene i classici cicli di retain e le race condition.

Domande frequenti

Cos'è Sendable in Swift in parole semplici?

Sendable è un marcatore che dice al compilatore: «questo tipo può essere trasferito in sicurezza tra thread». Le struct e le costanti sono solitamente Sendable per impostazione predefinita, le classi no, a meno che non sia specificato esplicitamente.

Quali tipi sono automaticamente conformi a Sendable?

I tipi valore (struct, enum) con proprietà Sendable, le classi finali con stato immutabile e tutti i tipi di base Swift: Int, String, Double, Bool, Array, Dictionary, Optional — sono automaticamente conformi a Sendable.

Cos'è @unchecked Sendable?

@unchecked Sendable è un modo per dichiarare una classe come Sendable senza controllo statico del compilatore. Lo sviluppatore garantisce la sicurezza da solo, spesso tramite lock o operazioni atomiche.

Perché Sendable è necessario per Actor?

Actor isola il suo stato, ma quando restituisce dati al codice esterno, questi dati attraversano il confine di isolamento. Sendable garantisce che il destinatario non incontri race condition nell'utilizzo di questi dati al di fuori dell'actor.

Come rendere una classe Sendable in Swift?

Aggiungi il protocollo Sendable a una classe finale, le cui proprietà siano tutte costanti di tipi Sendable. Se la classe usa lock, si può usare @unchecked Sendable, ma ciò richiede cautela.

Riepilogo

  • Sendable — un protocollo marcatore per il trasferimento sicuro di dati tra thread
  • Tipi valore sono automaticamente conformi a Sendable quando le condizioni sono soddisfatte
  • Classi richiedono una dichiarazione esplicita Sendable o @unchecked Sendable
  • Actor restituisce dati al codice esterno solo tramite tipi Sendable
  • @Sendable attributo di closure verifica la correttezza della cattura delle variabili
  • Il compilatore verifica staticamente la conformità Sendable, prevenendo race condition al momento della compilazione

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.

Discuti il progetto

Leggi anche