Last active
June 5, 2021 03:04
-
-
Save kristopherjohnson/d12877ee9a901867f599 to your computer and use it in GitHub Desktop.
Simple synchronization functions for Swift, wrapping the Cocoa NSLocking classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
/// Protocol for NSLocking objects that also provide tryLock() | |
public protocol TryLockable: NSLocking { | |
func tryLock() -> Bool | |
} | |
// These Cocoa classes have tryLock() | |
extension NSLock: TryLockable {} | |
extension NSRecursiveLock: TryLockable {} | |
extension NSConditionLock: TryLockable {} | |
/// Protocol for NSLocking objects that also provide lockBeforeDate() | |
public protocol BeforeDateLockable: NSLocking { | |
func lockBeforeDate(limit: NSDate) -> Bool | |
} | |
// These Cocoa classes have lockBeforeDate() | |
extension NSLock: BeforeDateLockable {} | |
extension NSRecursiveLock: BeforeDateLockable {} | |
extension NSConditionLock: BeforeDateLockable {} | |
/// Use an NSLocking object as a mutex for a critical section of code | |
public func synchronized<L: NSLocking>(lockable: L, criticalSection: () -> ()) { | |
lockable.lock() | |
criticalSection() | |
lockable.unlock() | |
} | |
/// Use an NSLocking object as a mutex for a critical section of code that returns a result | |
public func synchronizedResult<L: NSLocking, T>(lockable: L, criticalSection: () -> T) -> T { | |
lockable.lock() | |
let result = criticalSection() | |
lockable.unlock() | |
return result | |
} | |
/// Use a TryLockable object as a mutex for a critical section of code | |
/// | |
/// Return true if the critical section was executed, or false if tryLock() failed | |
public func trySynchronized<L: TryLockable>(lockable: L, criticalSection: () -> ()) -> Bool { | |
if !lockable.tryLock() { | |
return false | |
} | |
criticalSection() | |
lockable.unlock() | |
return true | |
} | |
/// Use a BeforeDateLockable object as a mutex for a critical section of code | |
/// | |
/// Return true if the critical section was executed, or false if lockBeforeDate() failed | |
public func synchronizedBeforeDate<L: BeforeDateLockable>(limit: NSDate, lockable: L, criticalSection: () -> ()) -> Bool { | |
if !lockable.lockBeforeDate(limit) { | |
return false | |
} | |
criticalSection() | |
lockable.unlock() | |
return true | |
} | |
// Examples | |
let lock = NSLock() | |
synchronized(lock) { | |
println("This is synchronized") | |
} | |
let result: String = synchronizedResult(lock) { | |
return "This is synchronized" | |
} | |
let didRun = trySynchronized(lock) { | |
println("This was synchronized with a trySynchronized") | |
} | |
println("didRun: \(didRun)") | |
let limit = NSDate(timeIntervalSinceNow: 1.0) | |
let didRunBeforeDate = synchronizedBeforeDate(limit, lock) { | |
println("This was synchronized with a time limit"); | |
} | |
println("didRunBeforeDate: \(didRunBeforeDate)") | |
let recursiveLock = NSRecursiveLock() | |
synchronized(recursiveLock) { | |
println("This is synchronized with a recursive lock") | |
synchronized(recursiveLock) { | |
println("This is synchronized with the same recursive lock") | |
} | |
} |
I've updated this for Swift 3 here: https://gist.github.com/einsteinx2/00b9ebd962f3a0f6c9e758f842e4c6f9
@mohamede1945: @NoEscape is no longer necessary as it's the default in Swift 3 and is deprecated.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you for the great and simple functions.
I think you might need to use @NoEscape for the passed closures.