11

How does one compare objects in Objective-C?

Is it as simple as == ?

I want to check an array for an object and if it doesnt exist add it to the array otherwise, remove it from the array.

Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
some_id
  • 29,466
  • 62
  • 182
  • 304

4 Answers4

22

Comparing objects in Objective-C works much the same as in Java or other object-oriented languages:

  • == compares the object reference; in Objective-C, whether they occupy the same memory address.
  • isEqual:, a method defined on NSObject, checks whether two objects are "the same." You can override this method to provide your own equality checking for your objects.

So generally to do what you want, you would do:

if(![myArray containsObject:anObject]) {
    [myArray addObject:anObject];
}

This works because the Objective-C array type, NSArray, has a method called containsObject: which sends the isEqual: message to every object it contains with your object as the argument. It does not use == unless the implementation of isEqual: relies on ==.

If you're working entirely with objects that you implement, remember you can override isEqual: to provide your own equality checking. Usually this is done by comparing fields of your objects.

Tim
  • 59,527
  • 19
  • 156
  • 165
  • :) Great. Thanks a lot for this. I am using == and it seems to work. What is more efficient? Could I encounter any problems with the ==? I will use containsObject, but I would just like to know. – some_id Feb 20 '11 at 02:23
  • 1
    `==` is generally more efficient as it's a single arithmetic comparison, rather than a (potentially extensive) custom comparison involving a method call, but using `isEqual:` is much more reliable and will almost always deliver better results. It's more forward-compatible too - if you need a new `isEqual:` implementation in the future, not only will you have to write it, you'll need to recode all your `==` as `isEqual:` at that point. If you do it now, you can just implement `isEqual:` to use `==` and change it later as needed. – Tim Feb 21 '11 at 02:27
  • 1
    The relevant technical terms here are *identity* and *equality*. `==` asks if they are identical (are they the same object instance) while `isEqual` asks if they are equal (where sometimes, depending on type semantics, two separate instances are considered equal). – AlexChaffee Jan 22 '13 at 23:39
11

Every Objective-C object has a method called isEqual:.

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isEqual:

So you would want to override this for your custom object types.

One particular important note in the documentation:

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.

vdsf
  • 1,608
  • 2
  • 18
  • 22
  • 1
    The method is `isEqual:` (with a colon). The colon makes a huge difference. – dreamlax Feb 20 '11 at 10:50
  • +1 for adding the comment about overriding the hash. It seems that containsObject will use the hash method and ignore isEqual: in certain situations. – Mike M Nov 13 '13 at 17:37
4

== will compare the pointer, you need to override

- (BOOL)isEqual:(id)anObject
CiNN
  • 9,752
  • 6
  • 44
  • 57
3

Implement isEqual: and hash

Per the Apple documentation on NSObject you need to implement isEqual: and hash at a minimum. Below you'll find one way to implement object equality, of course how to implement hash enters the land of serious debate here on StackOverflow, but this will work. General rule - you need to define what constitutes object equality and for each unique object they should have a unique hash. It is best practice to add an object specific equality method as well, for example NSString has isEqualToString:.

- (BOOL)isEqual:(id)object
{
    BOOL result = NO;

    if ([object isKindOfClass:[self class]]) {
        CLPObject *otherObject = object;
        result = [self.name isEqualToString:[otherObject name]] &&
        [self.shortName isEqualToString:[otherObject shortName]] &&
        [self.identifier isEqualToString:[otherObject identifier]] &&
        self.boardingAllowed == [otherObject isBoardingAllowed];
    }

    return result;
}

- (NSUInteger)hash
{
    NSUInteger result = 1;
    NSUInteger prime = 31;

    result = prime * result + [_name hash];
    result = prime * result + [_shortName hash];
    result = prime * result + [_identifier hash];
    result = prime * result + _boardingAllowed;

    return result;
}
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126