0

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:

  1. When a value is set, a strong-key/weak-value pair is added to NSMapTable. The key is a Watcher class that only NSMapTable holds a reference to (that's why it has to be strong). The value is the actual value that is to be stored.
  2. 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 only NSMapTable holds a reference to), which, when doing so, warns the WeakValue class.

My question is twofold:

  1. 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, but watcherWillDisappear is not called. Why doesn't it work?
  2. 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)
Community
  • 1
  • 1
Alex
  • 5,009
  • 3
  • 39
  • 73
  • This might be related: http://stackoverflow.com/questions/28670796/can-i-hook-when-a-weakly-referenced-object-of-arbitrary-type-is-freed. – Martin R Mar 06 '15 at 13:52
  • 1
    "(missing feature, anyone?)" That feature would come at a big price - weak pointers would now be "listeners" that needed to be tracked and notified, and the cost of that would outweigh the benefit of this marginal use case. – Airspeed Velocity Mar 06 '15 at 14:21
  • @MartinR Yes, that's pretty much what I wanted to do, thanks! – Alex Mar 07 '15 at 09:22
  • @AirspeedVelocity Fine with me, as long as there's a way to be notified when a weak value is deallocked. – Alex Mar 07 '15 at 09:23

0 Answers0