Is there a way to determine if a class is suitable as a key and will work as you expect, for example I want to use NSIndexPath as a key in NSDictionary but I don't know for certain if two different NSIndexPath instances with the same integer values will always return the same hash value.
3 Answers
Apple's NSObject's isEqual document says:
If two objects are equal, they must have the same hash value. This last point is particularly important if you define isEqual: in a subclass and intend to put instances of that subclass into a collection. Make sure you also define hash in your subclass.
Look the following code:
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:0 inSection:0];
NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:0 inSection:0];
NSObject *obj1 = [[NSObject alloc] init];
NSObject *obj2 = [[NSObject alloc] init];
NSLog(@"NSIndexPath isEqual's Result: %d", [indexPath1 isEqual:indexPath2]);
NSLog(@"NSObject isEqual's Result: %d", [obj1 isEqual:obj2]);
Output Result:
NSIndexPath isEqual's Result: 1
NSObject isEqual's Result: 0
The implementation of NSObject isEqual is that comare the address of two objects, and hash implementation is that return object's address.
NSIndexPath is inherited from NSObject, according to NSIndexPath isEqual output result, NSIndexPath's isEqual implementation should override superclass's isEqual method, and NSIndexPath also override superclass's hash method.
In attition, NSIndexPath also conform to the NSCopying protocol.
So NSIndexPath can be used as the Key class of NSDictionary.
-
1So you have to test if NSObjects implementation of isEqual: and hash are overridden and assume always will be, which is not unreasonable. I might raise a bug against apple as I think whether a class overrides isEqual: and hash should be documented. – Nathan Day Apr 18 '12 at 02:23
-
I agree with you! Apple's document does not clear enough in isEqual: and hash method. – xzgyb Apr 18 '12 at 02:51
-
1@NathanDay: I think you should raise a bug if there's a class for which it would make any sense at all to have those methods overridden but they aren't. – Chuck Apr 18 '12 at 05:54
-
6You need to be careful with NSIndexPath, though - the framework might give you UIMutableIndexPath objects for table views, and they *do not* always "match" an NSIndexPath with the same value. (just tested with iOS 7) – Eiko Sep 19 '13 at 19:11
How an object behaves as a key depends on how it implements isEqual:. This will determine whether two keys collide.
For example, index paths are equal - and therefore will collide - when the paths have the same set of indexes. So two distinct objects describing the same path will be seen by the dictionary as the same key... probably how you'd like it to be.

- 62,181
- 10
- 95
- 136
-
1My understanding is the value of hash is also important, I imagine that it is a good guess that NSIndexPaths implement isEqual: and hash in a way that will behave as we expect. But is that all there is, just a good guess? I was hopping for a protocol or documentation saying that the methods isEqual: and hash are overridden instead of depending on NSObjects implementation. – Nathan Day Apr 18 '12 at 01:09
-
An object is equal if its hash value is the same as the other's hash value, usually. So this makes hash very important as well. For a key you MUST have a class that reliably produces the same hash value for the same value of the object, and a distinct hash value for each value that the object could be. Then an easy way to compare the two values would be to see if their hashes match :). – borrrden Apr 18 '12 at 01:13
-
1According to Apple's documentation for NSDictionary, key objects must also conform to the NSCopying protocol, which NSIndexPath does. – bneely Apr 18 '12 at 01:13
There are three requirements for NSDictionary keys:
- Support the NSCopying protocol
- Reasonable -hash method
- isEqual
NSIndexPath should be fine.

- 9,650
- 2
- 38
- 34
-
But how do you know, I imagine NSIndexPath should be fine, but I don't know for certain. In fact I only know NSString is OK because it is used so often. NSNumber, NSDate, NSURL I ASSUME are OK, NSValue I don't know, maybe this is a bug in the documentation. – Nathan Day Apr 18 '12 at 01:34
-
Well, there's only one sure way to find out - try it! :-) If you look at NSIndexPath.h, you'll see it obeys the NSCopying protocol. You can also see that it has a "_hash" instance variable. And we know that it supports isEqual, so as far as I can tell it should work fine. This is a good place to use a unit test. And, yes, the documentation should be better. – EricS Apr 18 '12 at 02:22