WeakMapTable.swift 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import Foundation
  2. // MARK: - WeakMapTable
  3. final public class WeakMapTable<Key, Value> where Key: AnyObject {
  4. private var dictionary: [Weak<Key>: Value] = [:]
  5. private let lock = NSRecursiveLock()
  6. // MARK: Initializing
  7. public init() {
  8. }
  9. // MARK: Getting and Setting Values
  10. public func value(forKey key: Key) -> Value? {
  11. let weakKey = Weak(key)
  12. self.lock.lock()
  13. defer {
  14. self.lock.unlock()
  15. self.installDeallocHook(to: key)
  16. }
  17. return self.unsafeValue(forKey: weakKey)
  18. }
  19. public func value(forKey key: Key, default: @autoclosure () -> Value) -> Value {
  20. let weakKey = Weak(key)
  21. self.lock.lock()
  22. defer {
  23. self.lock.unlock()
  24. self.installDeallocHook(to: key)
  25. }
  26. if let value = self.unsafeValue(forKey: weakKey) {
  27. return value
  28. }
  29. let defaultValue = `default`()
  30. self.unsafeSetValue(defaultValue, forKey: weakKey)
  31. return defaultValue
  32. }
  33. public func forceCastedValue<T>(forKey key: Key, default: @autoclosure () -> T) -> T {
  34. return self.value(forKey: key, default: `default`() as! Value) as! T
  35. }
  36. public func setValue(_ value: Value?, forKey key: Key) {
  37. let weakKey = Weak(key)
  38. self.lock.lock()
  39. defer {
  40. self.lock.unlock()
  41. if value != nil {
  42. self.installDeallocHook(to: key)
  43. }
  44. }
  45. if let value = value {
  46. self.dictionary[weakKey] = value
  47. } else {
  48. self.dictionary.removeValue(forKey: weakKey)
  49. }
  50. }
  51. // MARK: Getting and Setting Values without Locking
  52. private func unsafeValue(forKey key: Weak<Key>) -> Value? {
  53. return self.dictionary[key]
  54. }
  55. private func unsafeSetValue(_ value: Value?, forKey key: Weak<Key>) {
  56. if let value = value {
  57. self.dictionary[key] = value
  58. } else {
  59. self.dictionary.removeValue(forKey: key)
  60. }
  61. }
  62. // MARK: Dealloc Hook
  63. private var deallocHookKey: Void?
  64. private func installDeallocHook(to key: Key) {
  65. let isInstalled = (objc_getAssociatedObject(key, &deallocHookKey) != nil)
  66. guard !isInstalled else { return }
  67. let weakKey = Weak(key)
  68. let hook = DeallocHook(handler: { [weak self] in
  69. self?.lock.lock()
  70. self?.dictionary.removeValue(forKey: weakKey)
  71. self?.lock.unlock()
  72. })
  73. objc_setAssociatedObject(key, &deallocHookKey, hook, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  74. }
  75. }
  76. // MARK: - Weak
  77. private final class Weak<T>: Hashable where T: AnyObject {
  78. private let objectHashValue: Int
  79. weak var object: T?
  80. init(_ object: T) {
  81. self.objectHashValue = ObjectIdentifier(object).hashValue
  82. self.object = object
  83. }
  84. func hash(into hasher: inout Hasher) {
  85. hasher.combine(self.objectHashValue)
  86. }
  87. static func == (lhs: Weak<T>, rhs: Weak<T>) -> Bool {
  88. return lhs.objectHashValue == rhs.objectHashValue
  89. }
  90. }
  91. // MARK: - DeallocHook
  92. private final class DeallocHook {
  93. private let handler: () -> Void
  94. init(handler: @escaping () -> Void) {
  95. self.handler = handler
  96. }
  97. deinit {
  98. self.handler()
  99. }
  100. }