Skip to content

Instantly share code, notes, and snippets.

@levibostian
Last active July 1, 2025 14:57
Show Gist options
  • Save levibostian/5cd7e93e17bcc863820503d73c0d649a to your computer and use it in GitHub Desktop.
Save levibostian/5cd7e93e17bcc863820503d73c0d649a to your computer and use it in GitHub Desktop.
Swift Atomic property wrapper using DispatchQueue
import Foundation
/**
Guarantee the wrapped value is only ever accessed from one thread at a time.
Inspired from: https://github.com/RougeWare/Swift-Atomic/blob/master/Sources/Atomic/Atomic.swift
*/
@propertyWrapper
public struct Atomic<DataType: Any> {
fileprivate let exclusiveAccessQueue = DispatchQueue(label: "Atomic \(UUID())", qos: .userInteractive)
fileprivate var unsafeValue: DataType
/// Safely accesses the unsafe value from within the context of its exclusive-access queue
public var wrappedValue: DataType {
get { exclusiveAccessQueue.sync { unsafeValue } }
set { exclusiveAccessQueue.sync { unsafeValue = newValue } }
}
/// Safely access the unsafe value and keep a lock on it to perform operations on it before letting go.
public mutating func lock(_ block: (inout DataType) -> Void) {
exclusiveAccessQueue.sync {
// Create reference to we can modify the data
var existingValue = unsafeValue
// By passing the existingValue into the block with `inout`, it can be modified in that block.
block(&existingValue)
// Set the new value to the modified version.
self.unsafeValue = existingValue
}
}
/**
Initializer that satisfies @propertyWrapper's requirements.
With this initializer created, you can assign default values to our wrapped properties,
like this: `@Atomic var foo = Foo()`
*/
public init(wrappedValue: DataType) {
self.unsafeValue = wrappedValue
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment