Thread-local value wrappers give threads their own independent instance of the wrapped value. Setting or mutating one thread's value has no effect on another thread's value.
The defaultValue (or value for ReadonlyThreadLocal) passed into the wrapper's initializer is evaluated lazily at most once per thread. This ensures each thread has its own distinct value.
Thread-local wrapper method calls are restricted to synchronous contexts only. This ensures that no suspension points are hit, which may cause executer switches.
Important
Thread-local wrappers must be nonisolated and declared as global constants or static properties to avoid unexpected behavior and memory leaks.
Use ThreadLocal when the wrapped value can be read and overwritten arbitrarily, such as tracking a count.
import ThreadLocal
nonisolated let currentCount = ThreadLocal(defaultValue: 0)
// Get the current thread's wrapped value.
let count: Int = currentCount.get()
// Set the current thread's wrapped value.
currentCount.set(count + 1)Use ScopedThreadLocal when the wrapped value is temporarily scoped to synchronous operations, such as passing a context object down the call stack.
import ThreadLocal
nonisolated let currentContext = ScopedThreadLocal(defaultValue: Context())
// Get the current thread's scoped wrapped value (for global scope, returns the 'defaultValue').
let context: Context = currentContext.get()
// Set thread-local value for the duration of a synchronous operation (scope).
currentContext.withValue(context.withName("John Doe")) {
// Calling 'currentContext.get()' will return the scoped value.
}
// The thread-local value will be reverted back to 'context' automatically after the operation. Use ReadonlyThreadLocal when the wrapped value does not need to be overwritten, such as a thread-local cache.
import ThreadLocal
nonisolated let currentCache = ReadonlyThreadLocal(value: Cache())
// Get the current thread's wrapped value.
let cache: Cache = currentCache.get()Add the swift-thread-local SPM package to your package's dependency list:
dependencies: [
.package(url: "https://github.com/ben-smith-dev/swift-thread-local", from: "1.0.0"),
]Then add the ThreadLocal product to a target's dependency list:
dependencies: [
.product(name: "ThreadLocal", package: "swift-thread-local"),
]Add swift-thread-local to your project as a package dependency.
This package does not collect data or use required reason APIs.
Apple's privacy requirements
This project is currently not accepting Pull Requests.
However, feedback is welcome! Please feel free to open an issue to report bugs, suggest improvements, or discuss feature requests.
This package is available under the MIT license, see LICENSE for details.