Better way to maintain list of weak class references?

I have the need to maintain a set of weak references (delegates) so that any currently alive referrence gets notified when some event happens. I picked up a technique posted somwhere on the web, whereby you keep an array of structures where the structure contains a single weak reference:


private struct WeakThing<T: AnyObject> {
  weak var value: T?
  init (value: T) {
    self.value = value
  }
}


I declare a protocol (which in 7b4 now must be @objc):

@objc protocol UserWatcher: AnyObject {
  func userUpdated(user: User)
}
final class User: NSObject {
  private var watchers = [WeakThing<UserWatcher>]()
  ...


The watchers are used here:

  for wo in watchers {
    if let delegate = wo.value {
      dispatch_async(dispatch_get_main_queue()) {
      delegate.userUpdated(self)
    }
  }


Not shown is (future) code to remove the WeakThing structure if the value has gone to nil.


Is there a better way to do this?

I dunno about "a better way", but you could save yourself some trouble by using NSMapTable, which is an existing way — and relieves you of the need to write the future code to clean up the array.

In practical terms, I think that's about as well as you can do right now, at least in pure Swift.


In an ideal world, you could use (or write) a generic WeakSet struct that would hide the wrappers from you but otherwise behave like a Set. That doesn't currently exist in the stdlib, and unfortunately, it appears to be complex to implement on your own -- at least if you want to do it as an exact analogue of Set. It's not difficult coding, but there are a lot of piddly little methods and support types to implement and then maintain in light of future stdlib updates.


This seems like a case where some sort of delegation feature in the language would be of help. All you'd need to do is transform objects on their way in and out.


In the meantime, you can separate out this logic into a simple DelegateList struct or just use NSHashTable.weakObjectsHashTable().

When you do this, remember to keep thread-safety in mind. You object will be deallocated on the thread it last gets released from (which may be on some async dispatch queue if you ever use it like that). That means you need to deal with a collection which might change its items' number and position at unpredictable times.


That's one of the reasons why most implementers of this kind of thing keep the collection layout fixed and set the corresponding items to nil when the weakly referenced object is deallocated.

Thaks for all the comments.


I should add that classes are **suppose** to deregister in deinit - so in the end there shouldn't be a case where the value is nil.


1) It turns out if I make the structure non-generic, I can simplfy the code a bit:


protocol UserWatcher: AnyObject {
  func userUpdated(user: User)
}
private struct WeakThing {
  weak var value: UserWatcher?
  init (value: UserWatcher) {
    self.value = value
  }
}
final class User {
  private var watchers = [WeakThing]()


2) I would only add or delete listeners on the main thread, so not worried about threading issues


3) I looked at NSMapTable. I'd seen it before but get a headache trying to figure it out, and google didn't help find a nice tutorial on it. So I'm guessing for my application, I'd want to use a 'strongToWeakObjectsMapTable - .use some unique identying string provided by the listener. If that listener gets released (on the main thread), then next time iterating through the table, I'd see a key but the value would be nil, and I could then later delete that object using the strongly held key.

I had some problems with this approach in previous versions in multithreaded environment. I do not know if it's something more reliable now, but im using something like this for now:


class WatcherKey: Hashable {
    var hashValue : Int { return ObjectIdentifier(self).hashValue }
}
func == (lhs: WatcherKey, rhs: WatcherKey) -> Bool {
    return lhs === rhs
}
class Watcher<T,U> {
    private var callbacks: [WatcherKey : T -> U]

    init(){
       callbacks = Dictionary<WatcherKey, T -> U>()
    }

    func addObserver(callback: T -> U) -> WatcherKey{
        let key = WatcherKey();
        callbacks[key] = callback;
        return key;
    }

     func removeObserver(key: WatcherKey){
        callbacks[key] = nil;
    }

    func notify(t: T){
        for callback in callbacks.values {callback(t)}
    }
    func notify(t: T) -> [U]{
        var resps = [U]()
        for callback in callbacks.values {resps.append(callback(t))}
        return resps
    }
    func notify(key:WatcherKey, t: T) -> U?{
        if let callback = callbacks[key] { return callback(t) }
        return nil
    }
}


I'd prefer just keep the Closure and not the complete object, and hence keep the key to remove in the future on deinit or other point. Need less magic than weak pointer on array, is more explicit, and more easy to make this thread-safety.

Very interesting - I just played with the code in a test project. However, I fail to see how this provides any safety in a multithreaded environment - you would need to do all callback modifications and notifications on the same dispatch queue, no?


Perhaps the closure can use 'weak self' to avoid a reference?


In any case, interesting use of Swift - thanks!

Yes... You need implement something to handler with multithreaded environment, personally i'm using the basic of GCD for this: Concurrent Queue, dispatch_sync for concurrent "reads", and dispatch_barrier_async for serialized “writes”. (tips from WWDC 2012 Session 712).

This is just a example of course.


And weak self on closures is the correct choice for "escaped" closures like this.

Better way to maintain list of weak class references?
 
 
Q