/// 线程安全字典
class ThreadSafeDictionary: Collection {
private let queue = DispatchQueue(label: "XNTech.ThreadSafeDictionary", attributes: .concurrent)
var dictionary: [V: T]
init(dict: [V: T] = [V:T]()) {
self.dictionary = dict
}
}
// MARK: - Properties
extension ThreadSafeDictionary {
/// 原始数据
var rawData: Dictionary {
self.queue.sync { return self.dictionary }
}
/// The first element of the collection.
///
/// If the collection is empty, the value of this property is `nil`.
///
/// let numbers = [10, 20, 30, 40, 50]
/// if let firstNumber = numbers.first {
/// print(firstNumber)
/// }
/// // Prints "10"
var first: (key: V, value: T)? {
self.queue.sync { return self.dictionary.first }
}
/// The number of key-value pairs in the dictionary.
///
/// - Complexity: O(1).
var count: Int {
self.queue.sync { return self.dictionary.count }
}
/// A Boolean value that indicates whether the dictionary is empty.
///
/// Dictionaries are empty when created with an initializer or an empty
/// dictionary literal.
///
/// var frequencies: [String: Int] = [:]
/// print(frequencies.isEmpty)
/// // Prints "true"
var isEmpty: Bool {
self.queue.sync { return self.dictionary.isEmpty }
}
/// The position of the first element in a nonempty dictionary.
///
/// If the collection is empty, `startIndex` is equal to `endIndex`.
///
/// - Complexity: Amortized O(1) if the dictionary does not wrap a bridged
/// `NSDictionary`. If the dictionary wraps a bridged `NSDictionary`, the
/// performance is unspecified.
var startIndex: Dictionary.Index {
self.queue.sync { return self.dictionary.startIndex }
}
/// The dictionary's "past the end" position---that is, the position one
/// greater than the last valid subscript argument.
///
/// If the collection is empty, `endIndex` is equal to `startIndex`.
///
/// - Complexity: Amortized O(1) if the dictionary does not wrap a bridged
/// `NSDictionary`; otherwise, the performance is unspecified.
var endIndex: Dictionary.Index {
self.queue.sync { return self.dictionary.endIndex }
}
/// A string that represents the contents of the dictionary.
var description: String {
self.queue.sync { return self.dictionary.description }
}
}
// MARK: - Immutable
extension ThreadSafeDictionary {
/// Returns the position immediately after the given index.
///
/// The successor of an index must be well defined. For an index `i` into a
/// collection `c`, calling `c.index(after: i)` returns the same index every
/// time.
///
/// - Parameter i: A valid index of the collection. `i` must be less than
/// `endIndex`.
/// - Returns: The index value immediately after `i`.
func index(after i: Dictionary.Index) -> Dictionary.Index {
self.queue.sync { return self.dictionary.index(after: i) }
}
subscript(key: V) -> T? {
set(newValue) {
self.queue.async(flags: .barrier) { [weak self] in
guard let self = self else { return }
self.dictionary[key] = newValue
}
}
get {
self.queue.sync { return self.dictionary[key] }
}
}
subscript(index: Dictionary.Index) -> Dictionary.Element {
self.queue.sync { return self.dictionary[index] }
}
/// A collection containing just the values of the dictionary.
///
/// When iterated over, values appear in this collection in the same order as
/// they occur in the dictionary's key-value pairs.
///
/// let countryCodes = ["BR": "Brazil", "GH": "Ghana", "JP": "Japan"]
/// print(countryCodes)
/// // Prints "["BR": "Brazil", "JP": "Japan", "GH": "Ghana"]"
///
/// for v in countryCodes.values {
/// print(v)
/// }
/// // Prints "Brazil"
/// // Prints "Japan"
/// // Prints "Ghana"
var values: Dictionary.Values {
get {
self.queue.sync { return self.dictionary.values }
}
}
}
// MARK: - Mutable
extension ThreadSafeDictionary {
/// Removes the given key and its associated value from the dictionary.
///
/// If the key is found in the dictionary, this method returns the key's
/// associated value. On removal, this method invalidates all indices with
/// respect to the dictionary.
///
/// var hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
/// if let value = hues.removeValue(forKey: "Coral") {
/// print("The value \(value) was removed.")
/// }
/// // Prints "The value 16 was removed."
///
/// If the key isn't found in the dictionary, `removeValue(forKey:)` returns
/// `nil`.
///
/// if let value = hues.removeValue(forKey: "Cerise") {
/// print("The value \(value) was removed.")
/// } else {
/// print("No value found for that key.")
/// }
/// // Prints "No value found for that key.""
///
/// - Parameter key: The key to remove along with its associated value.
/// - Returns: The value that was removed, or `nil` if the key was not
/// present in the dictionary.
///
/// - Complexity: O(*n*), where *n* is the number of key-value pairs in the
/// dictionary.
func removeValue(forKey key: V) {
self.queue.async(flags: .barrier) { [weak self] in
guard let self = self else { return }
self.dictionary.removeValue(forKey: key)
}
}
/// Removes all key-value pairs from the dictionary.
///
/// Calling this method invalidates all indices with respect to the
/// dictionary.
///
/// - Parameter keepCapacity: Whether the dictionary should keep its
/// underlying buffer. If you pass `true`, the operation preserves the
/// buffer capacity that the collection has, otherwise the underlying
/// buffer is released. The default is `false`.
///
/// - Complexity: O(*n*), where *n* is the number of key-value pairs in the
/// dictionary.
func removeAll() {
self.queue.async(flags: .barrier) { [weak self] in
guard let self = self else { return }
self.dictionary.removeAll()
}
}
}