Objective-c: custom class instance as dictionary key returns nil when key exists
nscopying, nsdictionary, objective-c
Solution
You should also implement `-isEqual:` and `-hash` on your custom objects.
For more info: Apple Documentation, NSHipster article
The reason you must do this is the keys can be copied when you put them in the dictionary and the default implementation of `isEqual` just does pointer comparison.
Problem
I have a custom class I'm using instances of as keys in a dictionary. The problem is, sometimes (not all the time) requesting a value from a dictionary with one of my custom instance keys returns `nil` when the key really is in the dictionary. I looked around the web on how to use custom objects as dictionary keys, and all I've been able to find is that you need to implement the `NSCopying` protocol, which I have done. My class looks like this: ``` // .h @interface MyObject: NSObject <NSCopying> @property (copy) NSString* someString; @property (copy) NSString* otherString; @property int someInt; + (instancetype) objectWithString:(NSString*)str; - (id) copyWithZone:(NSZone*)zone; @end // .m @implementation MyObject @synthesize someString; @synthesize otherString; @synthesize someInt; + (instancetype) objectWithString:(NSString*)str { id obj = [[self alloc] init]; [obj setSomeString:str]; [obj setOtherString:[str lowercaseString]; [obj setSomeInt:0]; return obj; } - (id) copyWithZone:(NSZone*)zone { id other = [[[self class] allocWithZone:zone] init]; [other setSomeString:self.someString]; [other setOtherString:self.otherString]; [other setSomeInt:self.someInt]; return other; } @end ``` Then I put some of these things in a mutable dictionary like this: ``` MyObject* key1 = [MyObject objectWithString:@"Foo"]; MyObject* key2 = [MyObject objectWithString:@"Bar"]; NSNumber* value1 = [NSNumber numberWithInt:123]; NSNumber* value2 = [NSNumber numberWithInt:456]; NSMutableDictionary* theDict = [[NSMutableDictionary alloc] init]; [theDict setObject:value1 forKey:key1]; [theDict setObject:value2 forKey:key2]; ``` Now what I want to do is just pop a key/value pair out of the dictionary, so I do that like this: ``` MyObject* theKey = [[theDict allKeys] firstObject]; NSNumber* theValue = [theDict objectForKey:theKey]; ``` And here's where I run into problems. Most of the time, this works fine. However, sometimes `objectForKey:theKey` returns `nil`. I've put a breakpoint in my code and can confirm that `theKey` is indeed in the `theDict`. What am I doing wrong here?