123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import Foundation
- // MARK: - WeakMapTable
- final public class WeakMapTable<Key, Value> where Key: AnyObject {
- private var dictionary: [Weak<Key>: Value] = [:]
- private let lock = NSRecursiveLock()
- // MARK: Initializing
- public init() {
- }
- // MARK: Getting and Setting Values
- public func value(forKey key: Key) -> Value? {
- let weakKey = Weak(key)
- self.lock.lock()
- defer {
- self.lock.unlock()
- self.installDeallocHook(to: key)
- }
- return self.unsafeValue(forKey: weakKey)
- }
- public func value(forKey key: Key, default: @autoclosure () -> Value) -> Value {
- let weakKey = Weak(key)
- self.lock.lock()
- defer {
- self.lock.unlock()
- self.installDeallocHook(to: key)
- }
- if let value = self.unsafeValue(forKey: weakKey) {
- return value
- }
- let defaultValue = `default`()
- self.unsafeSetValue(defaultValue, forKey: weakKey)
- return defaultValue
- }
- public func forceCastedValue<T>(forKey key: Key, default: @autoclosure () -> T) -> T {
- return self.value(forKey: key, default: `default`() as! Value) as! T
- }
- public func setValue(_ value: Value?, forKey key: Key) {
- let weakKey = Weak(key)
- self.lock.lock()
- defer {
- self.lock.unlock()
- if value != nil {
- self.installDeallocHook(to: key)
- }
- }
- if let value = value {
- self.dictionary[weakKey] = value
- } else {
- self.dictionary.removeValue(forKey: weakKey)
- }
- }
- // MARK: Getting and Setting Values without Locking
- private func unsafeValue(forKey key: Weak<Key>) -> Value? {
- return self.dictionary[key]
- }
- private func unsafeSetValue(_ value: Value?, forKey key: Weak<Key>) {
- if let value = value {
- self.dictionary[key] = value
- } else {
- self.dictionary.removeValue(forKey: key)
- }
- }
- // MARK: Dealloc Hook
- private var deallocHookKey: Void?
- private func installDeallocHook(to key: Key) {
- let isInstalled = (objc_getAssociatedObject(key, &deallocHookKey) != nil)
- guard !isInstalled else { return }
- let weakKey = Weak(key)
- let hook = DeallocHook(handler: { [weak self] in
- self?.lock.lock()
- self?.dictionary.removeValue(forKey: weakKey)
- self?.lock.unlock()
- })
- objc_setAssociatedObject(key, &deallocHookKey, hook, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
- }
- }
- // MARK: - Weak
- private final class Weak<T>: Hashable where T: AnyObject {
- private let objectHashValue: Int
- weak var object: T?
- init(_ object: T) {
- self.objectHashValue = ObjectIdentifier(object).hashValue
- self.object = object
- }
- func hash(into hasher: inout Hasher) {
- hasher.combine(self.objectHashValue)
- }
- static func == (lhs: Weak<T>, rhs: Weak<T>) -> Bool {
- return lhs.objectHashValue == rhs.objectHashValue
- }
- }
- // MARK: - DeallocHook
- private final class DeallocHook {
- private let handler: () -> Void
- init(handler: @escaping () -> Void) {
- self.handler = handler
- }
- deinit {
- self.handler()
- }
- }
|