Describe the implementation of a thread-safe singleton in Swift.
Instruction: Provide code for creating a thread-safe singleton class in Swift, and explain why it is thread-safe.
Updated
Official answer
Swift initializes a stored static property lazily and only once, including concurrent first access. That protects initialization; it does not make arbitrary mutable properties or methods on the resulting object thread-safe.
This complete singleton class is safe to share because its entire stored state is immutable and Sendable, not merely because shared is a static let:
final class AppConfiguration: Sendable {
static let shared = AppConfiguration()
let maximumAttempts: Int
private init() { maximumAttempts = 3 }
}
let first = AppConfiguration.shared
let second = AppConfiguration.shared
assert(first === second)
assert(first.maximumAttempts == 3)
The private initializer prevents ordinary callers from constructing another instance. final prevents subclassing, and the compiler checks this class's Sendable conformance. An immutable reference to a mutable non-Sendable object would not give the same guarantee.
If shared state must change, put the invariant inside an actor, isolate the class to MainActor when that matches its purpose, or use a carefully encapsulated synchronization primitive. Protect the whole read-modify-write operation and all access paths. Do not add unchecked Sendable simply to silence a diagnostic.
A singleton also creates a global dependency with long-lived state. Prefer injecting a dependency when callers need independent instances, test isolation or explicit lifetime control. Test concurrency behavior and invariant preservation separately from the once-only construction property.