Cocoa collections, an advisory note

Now that I'm doing actual useful iPhone development work I'm running into a few… shall we call them quirks? Talking about the iPhone specific stuff possibly needs to be [redacted] because of what's known on Twitter as the FUCKING NDA, but I think if something is also part of the OS X libraries then it is fair game.

I had cause in my recent application to use a NSDictionary (well a NSMutableDictionary but let's not quibble, shall we?). A NSDictionary is quite straightforward, it stores key-value pairs. Imagine that you have a Person class and you have some other data (not part of the Person directly) that you want to keep on a per-person basis. You might well decide to use a NSDictionary and store (as a value) a NSArray for each Person (as a key). That way you can quickly retrieve the data for any Person. Now the documentation says pretty clearly that it's going to copy the keys but the obvious implication isn't stated: that means you need to implement a copy operator for any class you plan on using as a key.

The thing is, nothing tests to make sure you do that. There's not even a warning if you don't but whatever default copy you get won't pass the comparison function. That means you can never say "Give me Bob's data" because the key for "Bob" won't be the same as the "Bob" object you're using. (And as an aside, yes I realize using the entire Person object as the key is slack. This was a temporary thing I was doing just to get the code running. In the particular case the "Person" object only consisted of a NSString anyway, so it wasn't that terrible.) You can happily stuff data in the Dictionary for "Bob" all day long but you'll get a nil when you try to retrieve the data.

So. If you're going to use a NSDictionary with custom key classes you'll want to implement the NSCopying protocol. I suspect you want to implement the isEqual message, and the documentation for that also mentions you need to implement hash. It's not that this isn't in the documentation exactly, but it's not front and center. If say you're writing code on your laptop in a car while driving to a Hooters where you plan on drinking a lot of beer. Hypothetically speaking.

This is pretty obvious, but I was surprised that I didn't get some sort of compile-time warning or error. Since the fix it make sure that object passed for the key was of a class that implemented NSCopying I still think the compiler could have detected this. (I'll admit it seems a little non-Objective-C-like but in my still newbie opinion Objective-C suffers from two much "try it it a runtime and see if it works" sort of behavior.) But it's just the sort of the thing you need to check yourself.