20

Let's say I have a some objects representing network connections. Once these connections are disconnected, the associated objects disappear. I don't want to hang on to a connection object which is no longer connected.

I also want to associate some data with these connections using a dictionary. So I might have the code:

class Connection { ... }
class Metadata { ... }

var metadata: [Connection: Metadata] = [:]

But the above code means that the dictionary will keep references to the Connection objects which I don't want. I'd prefer to have the associated entries be removed, ideally automatically, when the Connection objects disappear.

So I tried:

var metadata: [weak Connection: Metadata] = [:]

But this doesn't work. What is a good alternative solution to this?

2 Answers2

32

You are describing an NSMapTable. It gives you a dictionary-like thing with weak references to its keys and/or values.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 2
    Just a note to everyone writing Swift on the server: `NSMapTable` and `NSHashTable` does not exist on Linux, so you'll need to use an approach like Rob's answer. – Zoyt Jun 16 '17 at 23:01
  • Except that NSMapTable's weak keys are broken: key objects do not get actually released and are being held by internal implementation details. – Kentzo Apr 22 '21 at 22:41
  • @Kentzo I think "broken" is rather inappropriate. There are some good articles about how it works. – matt Apr 22 '21 at 23:26
  • I'm referring an issue as described [here](http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/). To my best knowledge it's still as broken as it was 8 years ago. – Kentzo Apr 22 '21 at 23:34
3

You can write a generic type for weak references like they did in How do I declare an array of weak references in Swift? Because you are doing this for the dictionary key, you have to go through some extra work to make it conform to Hashable, but it can be done.

Personally, though, I wouldn't use the connection objects as the key. I use a unique string identifier for the network request be the key (e.g., the taskIdentifier of the NSURLSessionTask).

That resolves the concern of the collection maintaining a strong reference to the request.

Regarding the removing of the item when the task is done, I just make this clean-up part of the task completion logic.

Community
  • 1
  • 1
Rob
  • 415,655
  • 72
  • 787
  • 1,044