NSDictionary is a storage container that holds data and accesses it by means of a key.
Keys used in NSDictionaries must conform to the
NSCopying protocol. The reason for this is that NSDictionaries can hold mutable objects as keys (
NSMutableDictionary, etc). Internally, NSDictionaries find values based on the key, but in order to speed up look up time, lookups are done based on the hash of the key. Since hashes are calculated as needed, if a key changes, the hash changes.
What this means is that mutable objects need to be copied into the
NSDictionary. Otherwise, the following might occur:
NSMutableDictionary * dict = [[NSMutableDictionary alloc] init]; NSMutableString * theKey = @"Some key"; [dict setObject:@"Hello World!" forKey:theKey]; [theKey appendString:@" to use"]; NSLog(@"%@", [dict objectForKey:theKey]);
We see that
theKey is changed after it's used as the key. If
NSMutableString did not implement
NSCopying, then the value (in this case,
@"Hello World!") would be lost forever. To get around this,
NSDictionary (and its subclasses) actually make a copy of the key and use that internally instead. Then, when you request an object, it doesn't have to worry about the hashes inexplicably changing.
What does this mean? For one thing, it means that you cannot use primitive data types as keys (int, float, char*, etc), since these types are non-copyable (they don't implement
NSCopying). Instead, you need to wrap them in another object, such as an
NSString, or something similar.
This also means that any class you want to use as a key in an
NSDictionary must implement the
- (id)copyWithZone:(NSZone *)zone method from
NSCopying. If you're using a pre-built class, you can declare a category with this method, since protocol (interface) conformance in Objective-C can be implicit, not just explicit like in Java.