Sendable — is een Swift-protocol dat typen markeert die veilig zijn voor overdracht tussen threads. Bij het werken met concurrentie (actor, async/await, Task) vereist de Swift-compiler dat alle gegevens die tussen geïsoleerde contexten worden verzonden, voldoen aan Sendable. Dit voorkomt het per ongeluk verzenden van onveilige typen die tot dataraces kunnen leiden. Het protocol fungeert als een contract: een type dat aan Sendable voldoet, garandeert de afwezigheid van interne niet-gesynchroniseerde toestand. Volgens WWDC 2021 is het Sendable-protocol een verplicht element bij het ontwerpen van veilige multithread-architectuur.
Belangrijkste
Sendable — is een protocol uit de standaard Swift-bibliotheek (SE-0302) dat typen markeert die veilig zijn voor overdracht tussen isolatiedomeinen. Onder isolatiedomein wordt een actor, een Task-taak of een @MainActor-context verstaan. Sendable bevat geen vereisten — het fungeert als een veiligheidsmarkering.
Vóór Swift 5.5 konden ontwikkelaars elk object tussen threads verzenden via DispatchQueue, en de compiler controleerde niet of dit veilig was. Sendable dicht deze leemte: nu volgt de compiler zelf inter-thread verzendingen en blokkeert onveilige. Dit maakt concurrente code nog voor uitvoering betrouwbaarder.
struct UserProfile: Sendable {
let name: String
let age: Int
}
class NonSendableClass {
var counter: Int = 0
}
In het voorbeeld kan UserProfile veilig tussen threads worden verzonden, omdat het een structuur is met constante eigenschappen van Sendable-typen. NonSendableClass zal een compilatiefout veroorzaken bij poging tot verzending via await of in Task.
Sendable-typen in Swift vallen in drie categorieën: waardetypen met Sendable-eigenschappen, finale klassen met onveranderlijke toestand en functies/closures gemarkeerd met @Sendable. De compiler leidt automatisch Sendable-conformiteit af voor waardetypen.
Struct, enum en tuple worden automatisch Sendable als al hun eigenschappen en bijbehorende waarden ook Sendable zijn. Dit is een conservatieve benadering: als zelfs één eigenschap niet aan Sendable voldoet, wordt het hele type niet als veilig beschouwd.
| Type | Sendable | Voorwaarde |
|---|---|---|
| Struct | Ja (zonder expliciete vermelding) | Alle eigenschappen Sendable |
| Enum | Ja (zonder expliciete vermelding) | Alle bijbehorende waarden Sendable |
| Final class | Ja (met expliciete vermelding) | Alle let-eigenschappen Sendable, geen var |
| Non-final class | Nee | Kan niet Sendable zijn vanwege overerving |
Alle ingebouwde Swift-typen — Int, String, Double, Bool, Optional, Array, Dictionary, Set — voldoen aan Sendable. Dit maakt typecompositie standaard veilig. De ontwikkelaar hoeft alleen op aangepaste klassen te letten.
@unchecked Sendable — is een mechanisme waarmee een klasse zich expliciet als Sendable kan verklaren, waarbij compilatorcontroles worden omzeild. De ontwikkelaar neemt de verantwoordelijkheid voor de draadveiligheid van een dergelijke klasse op zich. Dit is nuttig voor Objective-C-bruggen en geoptimaliseerde structuren.
@unchecked Sendable wordt toegepast wanneer een klasse intern veiligheid garandeert via vergrendelingen of atomaire bewerkingen, maar de compiler dit niet statisch kan controleren. Bijvoorbeeld een klasse met os_unfair_lock of pthread_mutex_t — de draadveiligheid wordt door code gegarandeerd, maar Swift ziet dit niet.
final class AtomicCounter: @unchecked Sendable {
private var value: Int = 0
private let lock = NSLock()
func increment() {
lock.lock()
value += 1
lock.unlock()
}
}
Gebruik @unchecked Sendable voorzichtig. Dit is een duidelijk signaal voor andere ontwikkelaars: „ik heb het gecontroleerd, het is veilig”. Een fout in de implementatie kan leiden tot moeilijk te traceren races. Voordat u @unchecked toepast, moet u ervoor zorgen dat het type echt niet kan worden herschreven als waardetype.
Actor en Sendable zijn twee kanten van dezelfde medaille. Actor isoleert zijn toestand, maar voor gegevensuitwisseling met de buitenwereld moet hij Sendable-typen retourneren. Als een actormethode een niet-Sendable type retourneert, geeft de compiler een waarschuwing of fout.
Wanneer een actor gegevens naar externe code verzendt, overschrijden deze gegevens de isolatiegrens. Sendable garandeert dat de ontvanger ze veilig buiten de actor kan gebruiken. De actor zelf blijft geïsoleerd — zijn interne toestand wordt niet onthuld.
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 — is een Sendable-structuur die alleen let-eigenschappen van Sendable-typen bevat. Deze benadering is best practice voor het extraheren van gegevens uit een actor. De momentopname van de toestand wordt op waarde verzonden en de actor verliest geen controle over zijn toestand.
@Sendable — is een attribuut voor functies en closures dat garandeert dat de closure geen niet-Sendable gegevens op een muteerbare manier vastlegt. Wanneer een closure naar Task of een actormethode wordt verzonden, moet deze Sendable zijn.
De compiler controleert of de @Sendable closure geen muteerbare verwijzingen naar klassen vastlegt. Het vastleggen van let-eigenschappen van Sendable-typen is toegestaan. Het vastleggen van een var-variabele van een referentietype zal een fout veroorzaken, omdat de closure gelijktijdig met mutatie kan worden uitgevoerd.
func performAsync(operation: @Sendable () -> Void) {
Task {
await operation()
}
}
let constant = "Safe"
var counter = 0
// counter — var vastleggen muteert teller, compilatiefout
performAsync { // ❌ Mutatie van vastgelegde var
print(constant)
}
De regel is eenvoudig: een @Sendable closure kan alleen gegevens vastleggen die zelf Sendable zijn en niet van buitenaf worden gemuteerd. Voor klassen is het vastleggen van een weak self verwijzing toegestaan als de klasse niet als Sendable is gemarkeerd. Dit voorkomt klassieke retain cycles en race conditions.
Veelgestelde vragen
Sendable — is een marker die tegen de compiler zegt: „dit type kan veilig tussen threads worden verzonden”. Structuren en constanten zijn meestal standaard Sendable, klassen — niet, tenzij dit expliciet is aangegeven.
Waardetypen (struct, enum) met Sendable-eigenschappen, finale klassen met onveranderlijke toestand, evenals alle basis Swift-typen: Int, String, Double, Bool, Array, Dictionary, Optional — voldoen automatisch aan Sendable.
@unchecked Sendable — is een manier om een klasse als Sendable te verklaren zonder statische compilatorcontrole. De ontwikkelaar garandeert de veiligheid zelf, vaak via vergrendelingen of atomaire bewerkingen.
Actor isoleert zijn toestand, maar bij het retourneren van gegevens aan externe code overschrijden deze gegevens de isolatiegrens. Sendable garandeert dat de ontvanger geen races tegenkomt bij het gebruik van deze gegevens buiten de actor.
Voeg het Sendable-protocol toe aan een finale klasse waarvan alle eigenschappen constanten van Sendable-typen zijn. Als de klasse vergrendelingen gebruikt, kan @unchecked Sendable worden toegepast, maar dit vereist voorzichtigheid.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook