[Objective C] Equality

April 17, 2017

Equality is a concept that “good” developer should have to avoid unexpected mistakes from software development.

With Value Types

Now, let’s jump straight to the issue, doing comparison in value types, we go like:

int a = 10;
int b = 10;
if (a == b) {
    NSLog(@"a is equal to b.");
} });

And clearly, the output will be: a is equal to b.

With value types, using == operator actually is bitwise equality, means they’re both the same binary representation.

Easy enough?

With Reference Types

NSString

2 With Reference Type variables are equal if they’re pointing to the same memory address. For example:

NSString *str1 = @"This is a string."; // address is 0x0008703c
NSString *str2 = @"This is a string."; // address is 0x0008703c

if (str1 == str2) {
    NSLog(@"str1 == str2");
}

So output will be str1 == str2;
Still easy, huh?

Further, in objective C, object has its own method to compare with others, it is isEqual, is this case, using isEqual is fine for now, but what is it? We will discover it afterward.

NSString *str1 = @"This is a string."; // address is 0x0008703c
NSString *str2 = @"This is a string."; // address is 0x0008703c

if ([str1 isEqual:str2]) {
    NSLog(@"str1 is equal to str2.");
} else {
    NSLog(@"str1 is not equal to str2.");
}

Of course, result will be str1 is equal to str2..

NSArray

How about others, I got a example:

NSArray *arr1 = @[@"1", @"3"]; // address is 0x78e60a90
NSArray *arr2 = @[@"1", @"3"]; // address is 0x78e72080

if (arr1 == arr2) {
    NSLog(@"arr1 == arr2");
}

if ([arr1 isEqual:arr2]) {
    NSLog(@"arr1 is equal to arr2.");
}

Now, result will be only arr1 is equal to arr2.. Conclusion, isEqual is still right while comparing 2 NSArray, but not for == operator anymore. And as we can see, the addresses of 2 arrays are now different. So we can not compare 2 arrays by using == make sense.

With NSArray, to compare them, in deed, it will compare their elements correspondingly. Here are what it does:

@implementation NSArray (Approximate)
- (BOOL)isEqualToArray:(NSArray *)array {
  if (!array || [self count] != [array count]) {
    return NO;
  }

  for (NSUInteger idx = 0; idx < [array count]; idx++) {
      if (![self[idx] isEqual:array[idx]]) {
          return NO;
      }
  }

  return YES;
}

- (BOOL)isEqual:(id)object {
  if (self == object) {
    return YES;
  }

  if (![object isKindOfClass:[NSArray class]]) {
    return NO;
  }

  return [self isEqualToArray:(NSArray *)object];
}
@end

Remember, in term of comparing collection types like NSArray, NSSet, NSDictionary, …, we should use what Cocoa’s benefits by using high-level APIs:

NSAttributedString -isEqualToAttributedString:
NSData -isEqualToData:
NSDate -isEqualToDate:
NSDictionary -isEqualToDictionary:
NSHashTable -isEqualToHashTable:
NSIndexSet -isEqualToIndexSet:
NSNumber -isEqualToNumber:
NSOrderedSet -isEqualToOrderedSet:
NSSet -isEqualToSet:
NSString -isEqualToString:
NSTimeZone -isEqualToTimeZone:
NSValue -isEqualToValue:

Question: What happen with NSString? Why it can use == operator? It means why 2 strings are pointing to the same address in memory. This turns out a concept which is really cool to optimize comparison. Called string interning. All the NSString will be saved in a shared pool, then if you initialize a NSString with same value as the previous one, string interning will recognize and assign the address of existing string of the pool to the new string. So they’re all pointing to the same address of memory. (NSNumber should use the same mechanism).

isEqual

In Apple’s document: https://developer.apple.com/reference/objectivec/1418956-nsobject/1418795-isequal?language=objc, it indicates If two objects are equal, they must have the same hash value. What is hash? We would talk about it in another topic, but this make us know isEqual stuff is not just simple, and give us idea about what it bases on to indicate the result of comparison.

Lesson learn

After this, we got some points:

  • Use high-level API while comparing NSObjects.
  • isEqual uses hash to indicate result.
  • string interning mechanism - cool stuff in some modern languages.

So hope you’re still happy coding and enjoying the post. And feel free to raise idea and comment.

Reference

  • http://nshipster.com/equality/
  • https://miafish.wordpress.com/2014/12/30/equals-vs/
  • http://pages.cs.wisc.edu/~bahls/cs302/PrimitiveVsReference.html