Sendable and thread-safety checking
Mark data as Sendable , write @Sendable closures, and choose between value types, actors, and @unchecked Sendable for thread-safe sharing.
Sendable and thread-safety checking is a free Swift Academy lesson on CoddyKit — lesson 3 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What is Sendable?
Sendable is Swift’s way to ensure data is safe to pass between concurrent tasks/actors.
- Most structs/enums are Sendable automatically.
- Classes are not Sendable by default.
- Use actors or @unchecked Sendable (rare, with manual safety).
Value types are easy
Structs with Sendable members are Sendable; passing them between tasks is safe.
// Value types with value-only stored properties are Sendable.
// They are safe to transfer across tasks.
struct Point: Sendable { let x: Int; let y: Int }
func shift(_ p: Point) -> Point { Point(x: p.x + 1, y: p.y + 1) }
// Use in parallel tasks
Task {
let p = Point(x: 1, y: 2)
async let a = shift(p)
async let b = shift(p)
let (p1, p2) = await (a, b)
print(p1, p2) // Point(x: 2, y: 3) Point(x: 2, y: 3)
}Classes: use actors
Actors make reference semantics safe across tasks by serializing access.
// Reference types (class) are not Sendable by default.
// Prefer actors to guard mutable state.
actor SafeCounter {
private var value = 0
func inc() { value += 1 }
func read() -> Int { value }
}
let counter = SafeCounter()
Task {
async let t1 = counter.inc()
async let t2 = counter.inc()
_ = await (t1, t2)
print(await counter.read()) // 2
}
// (Alternative) A plain class would need locks + @unchecked Sendable; see later.@Sendable closures
Mark closures @Sendable when they may run on other executors. Avoid capturing non-Sendable mutable state.
// Some APIs require closures to be @Sendable so captured values are safe.
func doTwice(_ f: @Sendable () -> Int) -> Int { f() + f() }
let base = 10
// Capturing an immutable value (let) is fine for @Sendable closures.
let result = doTwice { base + 1 }
print(result) // 22
// Detached tasks also use @Sendable under the hood:
let t = Task.detached { () -> Int in
// Do not capture non-Sendable mutable state here.
return 5 * 5
}
Task { print(await t.value) }@unchecked Sendable (advanced)
@unchecked Sendable opts out of compiler checks. Only use with strict internal synchronization (locks/queues) and as a last resort.
import Foundation
// Only when you KNOW it is safe: wrap with a lock and mark @unchecked Sendable.
final class Box<T>: @unchecked Sendable {
private var value: T
private let lock = NSLock()
init(_ value: T) { self.value = value }
func read() -> T {
lock.lock(); defer { lock.unlock() }
return value
}
func write(_ newValue: T) {
lock.lock(); value = newValue; lock.unlock()
}
}
let shared = Box<Int>(0)
let a = Task.detached { shared.write(1) }
let b = Task.detached { shared.write(2) }
Task {
_ = await (a.value, b.value)
print(shared.read()) // 1 or 2 (last writer wins, but no data race)
}Best practices
Guidelines:
- Prefer value types (Sendable-friendly).
- Use actors for shared mutable state.
- Write @Sendable closures; avoid capturing non-Sendable mutables.
- Only use @unchecked Sendable with rigorous synchronization.
Meaning of Sendable
Quick check: What does Sendable promise?
Recap
Recap: Use Sendable to model cross-task safety, prefer actors or value types, write @Sendable closures, and reserve @unchecked Sendable for well-synchronized internals only.
Frequently asked questions
Is the “Sendable and thread-safety checking” lesson free?
Yes — the full text of “Sendable and thread-safety checking” is free to read here on the web, and the Swift Academy course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.
What will I learn in “Sendable and thread-safety checking”?
Mark data as Sendable , write @Sendable closures, and choose between value types, actors, and @unchecked Sendable for thread-safe sharing. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Swift Academy?
No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 3, so you can start here or from the beginning and move at your own pace.
How long does the “Sendable and thread-safety checking” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Swift Academy lesson?
Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- TaskGroup for parallelism
- Actors & data isolation, nonisolated
- Sendable and thread-safety checking