tsing gao
tsing gao

Reputation: 148

Confused about the default isEqual and hash implements

I know that I can override hash and isEqual to check 2 instances equality. Xcode has the default snippet and doucument https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/ObjectComparison.html as following

- (BOOL)isEqual:(id)other
{
    if (other == self) {
        return YES;
    } else if (![super isEqual:other]) { //WHAT is this line mean ?
        return NO;
    } else {
        return <#comparison expression#>;
    }
}

- (NSUInteger)hash
{
    return <#hash expression#>;
}

Okay,

  1. other == self check two objects' pointers.

  2. if ![super isEqual:other], what is this line means ? If super object is not equal other, return NO ? Then it will always return NO, the step 3 will not be executed.

Am I wrong ?

Thanks.

Upvotes: 2

Views: 477

Answers (3)

HSG
HSG

Reputation: 1224

There is a slightly different between Hash and isEqual in Objective-C. First of all, NSObject checks equality with another object with the method isEqual: and basically, two objects may be equal to another, if they share a common set of observable properties.

Hashing in object comparison is an extra step in determining collection membership, which will faster your operation.

This will explain a little bit about hash and isEqual

  • Object equality is commutative ([a isEqual:b] --> [b isEqual:a])
  • If objects are equal, then their hash values must also be equal ([a isEqual:b] --> [a hash] == [b hash])
  • However, the converse does not hold: the hash values of two objects are equal do not mean that their values to be equal.

I hope this would be helpful. For reference, you can visit this link http://nshipster.com/equality/

Upvotes: 0

fishinear
fishinear

Reputation: 6336

It's a typical implementation in a class-hierarchy, that is, if your class derives from a super class that has its own meaningful isEqual: implementation. In that case it is wise to let the super class test the equality of the common properties. If the common part is not equal, then there is no chance that the derived objects are equal.

It is not needed if you derive directly from NSObject.

Actually, you'll need an extra step as well:

- (BOOL)isEqual:(id)other
{
    if (other == self) {
        return YES;
    } else if (![super isEqual:other]) {
        return NO;
    } else if (![other isKindOfClass:[MyClass class]]) {
        return NO; // comparing incompatible objects 
    } else {
        MyClass *myOther = (MyClass *) other;
        return <#compare between self and myOther#>;
    }
}

Upvotes: 4

Sulthan
Sulthan

Reputation: 130102

Let's look at one example of class inheritance:

@interface A : NSObject
@property (nonatomic, assign, readwrite) NSInteger fieldA;
@end 

@interface B : A
@property (nonatomic, assign, readwrite) NSInteger fieldB;
@end 

Now, if you want to implement equality on A, then you want to base it on the equality of fieldA:

// A equality
- (BOOL)isEqual:(id)other {
   ... 

   return [self fieldA] == [other fieldA];
}

When you are implementing equality on B, you need two conditions - first you have to make sure that fieldA is equal and then you have to make sure that fieldB is equal.

// B equality
- (BOOL)isEqual:(id)other {
   ... 

   return [super isEqual:other] && [self fieldB] == [other fieldB];
}

That's exactly what the [super isEqual:other] is doing - it checks the equality requirement of the superclass, that is fieldA.

To be honest, this isEqual: template is not very good. It is missing one of the most important things and that is the class equality check:

if (![other isMemberOfClass:[self class]]) {
   return NO;
}

You don't need this check only when you never mix instances of different classes. However, when you start putting instances of A and B into the same array/dictionary etc. you will have crashes when trying to compare instances of A with instances of B.

Upvotes: 0

Related Questions