Objective-C Objects Are Not Always Created Equal or Identitical


Take a look at Mattt Thompson's amazing article, and much more in-depth, article about this topic.

In my latest project I have to validate two custom objects by comparing them for their equality.  Most languages have a few techniques for accomplishing this task.

PHP - == and ===:

"When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values, and are instances of the same class. On the other hand, when using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class."

Java==, .equals(), compareTo(), and compare():

"==" - Comparing to see if a reference is null. Comparing two enum values. This works because there is only one object for each enum constant. You want to know if two references are to the same object

"a.equals(b)" - Compares values for equality. Because this method is defined in the Object class, from which all other classes are derived, it's automatically defined for every class. However, it doesn't perform an intelligent comparison for most classes unless the class overrides it. It has been defined in a meaningful way for most Java core classes. If it's not defined for a (user) class, it behaves the same as ==. It turns out that defining equals() isn't trivial; in fact it's moderately hard to get it right, especially in the case of subclasses. The best treatment of the issues is in Horstmann's Core Java.

"a.compareTo(b)" - Comparable interface. Compares values and returns an int which tells if the values compare less than, equal, or greater than. If your class objects have a natural order, implement the Comparable<T> interface and define this method. All Java classes that have a natural ordering implement this (String, Double, BigInteger, ...).

"compare(a, b)" - Comparator interface. Compares values of two objects. This is implemented as part of the Comparator<T> interface, and the typical use is to define one or more small utility classes that implement this, to pass to methods such as sort() or for use by sorting data structures such as TreeMap and TreeSet.


"A common tripup for programmers moving from other languages to Objective-C is dealing with the difference between equality and identity." - http://bit.ly/hC5BlJ

That statement couldn't have been closer to the truth.  Objective-C provides, like other languages, similar techniques for testing the equality and identity of objects.  You can use "==", "isEqual", and "isEqualTo".  While I won't go into the gory geeky details of the differences because this site does a ROCK SOLID job of doing that I will point out some gotchas and what I would consider best practices when implementing this feature.  Please note that if you want compare two different objects correctly then you custom classes, subclasses of NSObject, MUST implement/override isEqual and hash.

Here is the basic example to start out with in your object:

Doesn't seem too difficult does it?!  What I didn't pay attention to at the time was that my class contained properties that were primitive and thus trying to "hash" those values caused compiler error's.  In addition, when taking the hash of multiple properties it is more efficient to concatenate the result with XOR (^) as opposed to "+=".  Please note that this will NOT prevent you from having 100% accuracy.  For example, you could hash, "Cory Wiles" and "Wiles Cory"....they will end up having the same hash, but they don't have the same identity.  For my use case I don't have the need for a custom hash algorithm, but it is something to keep in mind when you are architecting your own classes.

The other area that I found myself banging my head against was that my implementation of isEqual kept failing for a property of another objective.  Just so happens that the other object was an enum value so I had to treat as an int.  Once I re-factored everything worked as expected.

Simple "hello example" snippet:

In summary, no matter what language that you use, IMHO, comparing objects is more than calling "==" and should NEVER be an after thought. If that is your mindset then you a) should quite programming immediately  and/or b) except HUGE headaches in the new future. There is a linear increase in complexity of your hash algorithm compared with the complexity of your class properties (primitive types, custom objects, NSArrays, NSDictionary, etc).