Sendable and Swift 6 Data-Race Safety
36.1 The Sendable Protocol
A type is Sendable if values can be safely shared across concurrency domains (tasks/actors).
Value types whose stored properties are all Sendable ✅ (implicitly, for non-public types)
Immutable final class with let Sendable properties ✅ (declare : Sendable)
❌ (unless internally synchronized: @unchecked Sendable with locks/Mutex)
@Sendable closures capture only Sendable values
struct Message: Sendable { let id: Int; let text: String }
final class Config: Sendable {
let apiKey: String
init(apiKey: String) { self.apiKey = apiKey }
}
final class Counter: @unchecked Sendable { // you promise thread safety
private let lock = NSLock()
private var value = 0
func increment() { lock.withLock { value += 1 } }
}
func run(_ work: @escaping @Sendable () async -> Void) { Task { await work() } }36.2 Swift 6 Language Mode: Complete Data-Race Safety
In the Swift 6 language mode, data races are compile-time errors. The compiler checks isolation boundaries, Sendable conformance, and global mutable state.
Region-based isolation (SE-0414) and sending parameters (SE-0430) let non-Sendable values be passed across boundaries when the compiler proves they're no longer used by the sender.
var globalCounter = 0 // ❌ Swift 6: global mutable state isn't concurrency-safe
nonisolated(unsafe) var legacyCounter = 0 // opt out (you guarantee safety)
let safeGlobal = 42 // ✅ immutable
@MainActor var uiState = 0 // ✅ isolated to the MainActorfunc makeReport() async -> Report {
let report = Report() // non-Sendable class
await uploader.upload(report) // OK if `report` isn't used afterward (region transfer)
return Report()
}36.3 Migration Strategy
Enable warnings first: -strict-concurrency=complete (Swift 5 mode), or upcoming feature flags in Package.swift.
Annotate UI code with @MainActor. Make models value types/Sendable. Convert shared mutable state to actors or Mutex-protected types.
Use @preconcurrency import for libraries not yet updated. Migrate module by module.
Switch to Swift 6 mode (swiftLanguageModes: [.v6] / Xcode build setting). Consider 6.2's approachable concurrency defaults for app targets.