1

I am reading the Programming with Objective-C . In the section of Determining Equality of Objects , it says the following words:

- When dealing with objects, the == operator is used to test whether two separate pointers are pointing to the same object:

if (firstPerson == secondPerson) {
    // firstPerson is the same object as secondPerson
}

- If you need to test whether two objects represent the same data, you need to call a method like isEqual:, available from NSObject:

if ([firstPerson isEqual:secondPerson]) {
    // firstPerson is identical to secondPerson
}

I get confused about the differences between == and isEqual with the above explanation, does it mean firstPerson == secondPerson is an alternative of [firstPerson isEqual:secondPerson] ?

Leem.fin
  • 40,781
  • 83
  • 202
  • 354
  • No. The isEqual contract in most languages extends to the facets of the particular objects rather than rigid pointer equality. E.g. isEqual for strings would compare the contents of each string, rather than the address of the char arrays they both held. See http://stackoverflow.com/questions/3741281/should-you-use-isequal-or – CodaFi Mar 30 '14 at 10:48
  • Go back a few chapters and read up on the difference between *object* and *reference*. – Hot Licks Mar 30 '14 at 14:27

3 Answers3

2
NSString *string1 = [[NSString alloc] initWithString:@"some string"];
NSString *string2 = [[NSString alloc] initWithString:@"some string"];
NSString *string3 = string2;

BOOL equal1 = (string1 == string2); // NO

BOOL equal2 = [string1 isEqual:string2]; // YES

BOOL equal3 = (string2 == string3); // YES

BOOL equal4 = [string2 isEqualToString:string3]; // YES
Igor Matyushkin
  • 778
  • 4
  • 4
  • 4
    `equal1` is actually `YES` ... (the compiler is so smart that it creates string literals only once ... even if you use `stringWithString`). – Martin R Mar 30 '14 at 10:55
  • Gotta love literal pointers. – CodaFi Mar 30 '14 at 10:55
  • Yep, I forgot about literal pointers :) Just updated answer. – Igor Matyushkin Mar 30 '14 at 11:01
  • They still equal in Xcode 5.1 :) you should alloc them – Basheer_CAD Mar 30 '14 at 11:03
  • `stringWithString:` does the same what `alloc...init` does. – Igor Matyushkin Mar 30 '14 at 11:04
  • @IgorMatyushkin, nope :) check it – Basheer_CAD Mar 30 '14 at 11:05
  • @IgorMatyushkin NSString is immutable. The copy constructor with a literal can, and does, just return self and wipe its hands. Heck, it's actually a compiler warning. – CodaFi Mar 30 '14 at 11:06
  • @IgorMatyushkin: I tried it with alloc/initWithString and got the same address (and a compiler warning). - Might be compiler dependent. – Martin R Mar 30 '14 at 11:08
  • Looks like Xcode 5.1 compiler brought something new to usage of `NSString`. – Igor Matyushkin Mar 30 '14 at 11:10
  • The only way you can get this to work is with the new container literals for strings. Change one or both of those to `@("some string")` and it will be realized at runtime with a character array, not a literal. – CodaFi Mar 30 '14 at 11:11
  • Here is the thing, if you use initWithString for the first str and initWithFormat for the second then you get different addresses, even though they have the same value. Maybe this is objective-c caching behavior – Basheer_CAD Mar 30 '14 at 11:16
  • I guess usage of `initWithFormat:` for every string make them to be a different objects. – Igor Matyushkin Mar 30 '14 at 11:18
  • Format strings are fundamentally runtime entities. Binary caching of string literals occurs because the strings are declared constant. Honestly, I'd just go with boxing a char array. – CodaFi Mar 30 '14 at 11:50
2

The definition of == is correct, it checks to see that they're pointing to the actual same pointer/memory address (ie. 0xffffff)

The key to understanding what you're asking is to think about what you mean by the word "equal". "equal" typically means, from the developer's point of view, that "these two objects contain the same data in the fields that I require for all practical purposes". You can have two user objects each with the same userID property but different times in lastUpdated - would you consider them equal? Depends on your use case. Most likely you would say yes because they're the same user. They were updated from the server at different times, so some fields differ, but for your implementation, they're equal.

In the case above, are they the same object? Definitely not. They point to different memory addresses. So == would be NO, whereas if you wrote your isEqual: method to check just the userID property, it would return YES

The definition of isEqual: is entirely up to the author of the class. isEqual: can be written to use == if you wanted. All you have to do, in your class, is to override the isEqual: method which is defined by the NSObject protocol.

If you have a custom object, use isEqual: to define what your definition of equal is. In the example of a user object, you might define:

- (BOOL)isEqual:(id)otherObject {
    if ([otherObject isKindOfClass:[self class]]) {
        MyClass *otherObjectAfterCast = (MyClass*)otherObject;
        
        if ([otherObjectAfterCast.userID isEqualToString:self.userID])
            return YES;
    }
    
    return NO;
}

Technically you'd probably want to use caseInsensitiveCompare: or something like that but you get the drift...

isEqual: can also be used to trigger other methods - in the case of NSString - calling isEqual: when both operands are strings results in a call to isEqualToString: - which is why the documentation recommends calling isEqualToString: if you know they're both strings, since it's a bit faster.

So, isEqual: is whatever you make of it, or whatever the class author has defined it to be.

This is also a pretty clear definition in the docs (for once lol): NSObject Protocol Reference

Hope this helps! Let me know if you need any further clarification.

Community
  • 1
  • 1
Jai Govindani
  • 3,181
  • 21
  • 26
  • Finally, an answer that doesn't try to use pointer-level equality on constants. – CodaFi Mar 30 '14 at 11:04
  • well '==' is hash comparison, right ? to be more accurate – Basheer_CAD Mar 30 '14 at 11:06
  • @Basheer_CAD: No. `==` is pointer comparison, nothing else. – Martin R Mar 30 '14 at 11:09
  • @MartinR, are you sure because in Apple docs they say 2 objects are equal of they have equal hash values – Basheer_CAD Mar 30 '14 at 11:12
  • @Basheer_CAD `If two objects are equal (as determined by the isEqual: method), they must have the same hash value. This last point is particularly important if you define hash in a subclass and intend to put instances of that subclass into a collection.` I'm pretty sure this just means your implementations of `isEqual:` and `hash` have to be linked in such a way that they return the same values on the same set of objects, no? From the language in the docs, anyways... – Jai Govindani Mar 30 '14 at 11:19
  • @JaiGovindani Absolutely. NSObject uses the pointer itself for the hash, but an object like NSString might hash its contents and return that. For more opaque data structures and complex objects, hashing is critical, but it's unnecessary for simpler objects. – CodaFi Mar 30 '14 at 11:23
  • @CodaFi awesome thanks for the confirmation. So basically it means that if two objects are equal, as per `isEqual:`, they must return the same value in `hash`. This doesn't necessarily mean that the converse is true, does it? Two objects can have the same `hash` but return NO for `isEqual:` - I would imagine one could easily write `hash` implementations for two entirely different classes that could return the same value, for whatever reason. – Jai Govindani Mar 30 '14 at 11:30
  • Ideally, yes, when the `hash` is the same `isEqual:` should return true as well. That's why it's a terrible idea to decouple `hash` and `isEqual:`. Going one way, the hash says the two pointers are equal, going the other, `isEqual:` says both hashes *should be* the same. – CodaFi Mar 30 '14 at 11:34
  • if ([[otherObject class] isKindOfClass:[self class]]) is actually not properly typed, it should be however.. if([otherObject isKindOfClass:[self class]]) the object's class can't be a kind of some class, but an object can be. – Ahmed Awad Jul 23 '17 at 08:20
  • @AhmedAwad you're right, thanks for catching that. Edited! – Jai Govindani Jul 24 '17 at 10:16
  • @Jai Govindani You're most welcome. – Ahmed Awad Jul 25 '17 at 09:14
0

The simple version is this.

== tells you if the pointers are the same object or not.

The isEqual: family of methods do something different. They tell you if the objects at the other end of the pointers are effectively the same based on some criteria such as the properties or ivars holding equal values or whatever logic is implemented in the method used. They may or may not be the exact same object.

uchuugaka
  • 12,679
  • 6
  • 37
  • 55