NSAttributedString | -isEqualToAttributedString: |
---|---|
NSData | -isEqualToData: |
NSData | -isEqualToData: |
NSDictionary | -isEqualToDictionary: |
NSHashTable | -isEqualToHashTable: |
NSIndexSet | -isEqualToIndexSet: |
NSNumber | -isEqualToNumber: |
NSOrderedSet | -isEqualToOrderedSet: |
NSSet | -isEqualToSet: |
NSString | -isEqualToString: |
NSTimeZone | -isEqualToTimeZone: |
NSValue | -isEqualToValue: |
NSString *a = @"Hello";
NSString *b = @"Hello";
BOOL wtf = (a == b); // YES (!)
NSString *a = @"Hello";
NSString *b = [NSString stringWithFormat:@"%@", @"Hello"];
BOOL wtf = (a == b); // NO (!)
To be perfectly clear: the correct way to compare two NSString objects is -isEqualToString:. Under no circumstances should NSString objects be compared with the == operator.
So what's going on here? Why does this work, when the same code for NSArray or NSDictionary literals wouldn't do this?
It all has to do with an optimization technique known as string interning, whereby one copy of immutable string values. NSString a and b point to the same copy of the interned string value @"Hello".
Again, this only works for statically-defined, immutable strings. Constructing identical strings with NSString +stringWithFormat: will objects with different pointers.
Interestingly enough, Objective-C selector names are also stored as interned strings in a shared string pool.
Object equality is commutative
([a isEqual:b] ⇒ [b isEqual:a])
If objects are equal, their hash values must also be equal
([a isEqual:b] ⇒ [a hash] == [b hash])
However, the converse does not hold: two objects need not be equal in order for their hash values to be equal
([a hash] == [b hash] ¬⇒ [a isEqual:b])