Why does an NSArray of NSStrings work as a key for NSMutableDictionary?

| | August 11, 2015

I’ve been trying to figure this out for a while and I’m not entirely clear on why or how this works.

I need to store a pair of identifiers (separately, so they can’t be concatenated together) that map to an object. Originally, I was using a top level NSMutableDictionary instance for this, with nested NSMutableDictionary objects underneath that. To retrieve the value of an identifier pair, I could then call:

[[myTopLevelDictionary objectForKey:key1] objectForKey:key2]

And this would work suitably well, even though keeping track of the nested NSMutableDictionary instances requires a bit of extra work.

Yesterday, I was wondering if there was any way to use a pair of NSString objects as a key directly. So I tried creating an NSArray instance with two NSString objects and using that as the key instead, and it worked:

NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSArray *key = [NSArray arrayWithObjects:@"A", @"B", nil];

[dict setObject:@"foobar" forKey:key];

NSLog(@"%@", [dict objectForKey:key]);
NSLog(@"%@", [NSArray arrayWithObjects:@"A", @"B", nil];

// Even this seems to work?
NSMutableArray *key2 = [NSMutableArray arrayWithObjects:@"A", @"B", @"C", nil];
[key2 removeLastObject];

NSLog(@"%@", key2);

All three cases will successfully print “foobar”. If I change the order of the NSString objects within the array, then the dictionary will return nil instead. If I add or remove NSString objects, again, the dictionary will correctly return nil. Only an NSArray object with the correct NSString objects containing the correct contents in the correct order seems to retrieve the appropriate value.

My question is… Why does this work, and how?

I know that hashing has something to do with it, but sending hash to an NSArray object just seems to return the object count, so I can’t imagine that has much to do with it. Then I figured maybe NSDictionary was trying to get the NSArray’s description and using that as a string based key, but I’m not sure how to test this theory since NSString’s hash isn’t the same as NSArray’s hash (so I can’t just use a NSString key that replicates the output of [[NSArray arrayWithObjects:@"A", @"B", nil] description]).

Don’t get me wrong, it’d be great if I could use NSArray/NSString/NSMutableDictionary like this, I just want to make sure that things are working the way I think they are and that this isn’t some kind of bizarre undefined behaviour or something.

Leave a Reply