小工具-线程安全字典

/// 线程安全字典 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() } } }