Skip to content

Instantly share code, notes, and snippets.

@Abeansits
Last active May 25, 2017 18:38
Show Gist options
  • Save Abeansits/ca58576908a98d7e9104c33002342087 to your computer and use it in GitHub Desktop.
Save Abeansits/ca58576908a98d7e9104c33002342087 to your computer and use it in GitHub Desktop.
A thread safe callback dictionary
import Foundation
/// A thread-safe container for mapping a String key to a `CallbackBlock`. A callback-block can be invoked individually or all at once.
public struct CallbackDictionary<ResultType> {
// MARK: - Initializing
public init() {}
// MARK: - Public Interface
/// The block that can be called.
public typealias CallbackBlock = (Result<ResultType>) -> Void
/// Appends another block and pairs it with the `key`. If the `key` already exists it will be overwritten.
/// Function is thread-safe.
public mutating func add(callback: @escaping CallbackBlock, for key: AnyHashable) {
// For now let's roll with a DispatchQueue.sync sollution even though it is very inefficient.
// If we see a problem with this sollution or Swift get's proper synchronization support
// we can change this implementation.
//
// More info: https://www.cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html#an-absence-of-threading-in-swift
//
syncingQueue.sync {
callbackMapper[key] = callback
}
}
/// Will try to remove the block that is associated with the passed in `key`.
/// The function is thread-safe.
public mutating func remove(for key: AnyHashable) {
syncingQueue.sync {
let _ = callbackMapper.removeValue(forKey: key)
}
}
/// Calls a specific block associated to the key passed in. If no block is found it's a NOP.
/// The function is thread-safe.
public func callBlock(for key: AnyHashable, with result: Result<ResultType>) {
syncingQueue.sync {
if let block = callbackMapper[key] {
block(result)
}
}
}
/// Calls all the blocks stored with the passed in results.
/// The function is thread-safe.
public func callAllBlocks(with result: Result<ResultType>) {
syncingQueue.sync {
callbackMapper.values.forEach { block in
block(result)
}
}
}
// MARK: - Private
/// A serial queue is used to secure access to resources.
private let syncingQueue = DispatchQueue(label: "com.syncing.queue.CallbackDictionary")
/// The actual storage of the string keys and their blocks. It's just a regular Dictionary.
private var callbackMapper = [AnyHashable: CallbackBlock]()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment