Do you really know the OC objects are equal?
Tags: objective-c
Comparing the equality of two objects is a common feature. The == operator compares not the object, but the two pointers themselves, which in general are not what we want. To determine whether an object is equal, you should use the method declared in the NSObject protocol isEqual: . In general, two different types of objects are always unequal.
If you already have some OC coding experience, you must have customized the isEqual: method. So you've come across some wonderful problems? Let's look at a piece of code first:
@interface Person: nsobject <nscopying>@property(nonatomic, copy)NSString*name;@end @implementation person- (BOOL) IsEqual: (ID) Object {if( Self= = object)return YES;if(! [Object Iskindofclass:[person class]])return NO;return[ Self. NameIsequaltostring:[object name]];} - (ID) Copywithzone: (Nszone *) Zone {person *person = [[Person Allocwithzone:zone] init]; Person. Name= Self. Name;returnperson;}@end- (voidTest {Person *person = [[Person alloc] init]; Person. Name= @"Lili";nsdictionary*dic = @{person: @1}; Person *personcopy = [person copy];IDObject = [dic objectforkey:personcopy];NSLog(@"%@", [person isequal:personcopy]? @"YES": @"NO");//output: YES NSLog(@"%@", object);//output: (NULL)}
This code defines the class: person, implements the isEqual: method, and implements the NSCopying protocol. In the test, the person object is placed in the dictionary as a key. Then copy a new object with the person object: Personcopy. But with this personcopy as key from the dictionary to fetch the corresponding value, actually did not fetch, the output is (null). But we have judged the person and the Personcopy object: and [person isEqual:personCopy] it is indeed equal.
So where's the problem? System problems? No way. Let's first look at the key requirements in Nsdictionary:
In the dictionary, keys are unique. That is, no two keys are equal in a dictionary (judged by isEqual: ). In general, a key can be any object that implements the NSCopying protocol
NSCopyingThe protocol only defines the copyWithZone: method, and we do it, not the problem. What if it's not the problem isEqual: ? This method is declared in the NSObject protocol. Take a look at this method one of the explanations:
If two objects are equal, then they must have the same hash value. This is especially important if your custom type defines a isEqaul: method and intends to put its instance into the collection. You should make sure that the method is defined as well as the isEqual: hash method.
In other words, NSObject there are two methods used to determine equivalence in the protocol:
- (BOOL)isEqual:(id)object; - (NSUinteger)hash;
NSObjectThe default implementation of the class for both methods is that the two objects are equal only if and only if their pointer values are exactly equal. If you want to implement these methods correctly in your custom classes, you must first understand their conventions. If isEqual: a method determines that two objects are equal, its hash method must return the same value. However, if a method of two objects hash returns the same value, the isEqual: method may not necessarily consider the two equal.
Oh, it turns out that's the problem. So let's write a hash way to see:
//PERSON.M-(Nsuinteger) hash {return[ Self. NameHash];}//Test- (voidTest {Person *person = [[Person alloc] init]; Person. Name= @"Lili";nsdictionary*dic = @{person: @1}; Person *personcopy = [person copy];IDObject = [dic objectforkey:personcopy];NSLog(@"%@", [person isequal:personcopy]? @"YES": @"NO");//output: YES NSLog(@"%@", object);//output: 1}
OK, this time there is no problem.
Conclusion: isEqual: the method should be realized at the same time hash .
Do you really know the OC objects are equal?