Not long after I posted this question, I got an idea of how a generic weak storage box could be implemented, that knows and sends an event when the weak value it holds is deallocked.
Here's what I mean by that (an example implementation that doesn't work):
class WeakValue<T: AnyObject> {
weak var value: T? {
didSet { /* Send event here when value is changed __or becomes nil__ */ }
}
}
This doesn't work. For some reason, property observers are not triggered when they observe a weak var and it becomes nil (missing feature, anyone?).
So, here's the idea I had:
private class Watcher {
weak var delegate: WeakValue<AnyObject>?
init(delegate d: WeakValue<AnyObject>) { delegate = d }
deinit { delegate?.watcherWillDisappear() }
}
public class WeakValue<T: AnyObject> {
private let storage = NSMapTable.strongToWeakObjectsMapTable()
public init() {}
public init(value v: T?) { value = v; reloadValue() }
public weak var value: T? { didSet { reloadValue() } }
private func reloadValue() {
storage.removeAllObjects()
if let v = value { storage.setObject(v, forKey: Watcher(delegate: unsafeBitCast(self, WeakValue<AnyObject>.self))) }
}
private func watcherWillDisappear() {
/* Event triggered here */
}
}
The idea was to use the functionality of NSMapTable
to my advantage. Here's how it should work:
- When a value is set, a strong-key/weak-value pair is added to
NSMapTable
. The key is a Watcher class that onlyNSMapTable
holds a reference to (that's why it has to be strong). The value is the actual value that is to be stored. - Whenever the value is deallocked,
NSMapTable
removes the key/value pair from its storage, which in turn deallocks the Watcher class (set as the key and which onlyNSMapTable
holds a reference to), which, when doing so, warns theWeakValue
class.
My question is twofold:
- This doesn't seem to work (I didn't test this on a Playground, I tested it on a real project): the test class I feed to
WeakValue
is deallocked, butwatcherWillDisappear
is not called. Why doesn't it work? - This is not very efficient, right? (creating a new
NSMapTable
for every weak value I want to store and for which I need an alert when deallocked)