[object compare: weHaveAProblem]

When using Objective-C Methods like compare: and similar methods like caseInsensitiveCompare: you should be aware of one possible problem:

  • Compare returns NSOrderedSame when two objects are considered equal
  • NSOrderedSame is also returned, if you call compare: on a nil-pointer!
  • Why is that?

    Because any method being called on a nil pointer returns nil.
    Which is the same as 0 (zero).
    Which is the same as NSOrderedSame.
    Ouch!

    Assume we have:
    NSString *stringa = @"huhu";
    NSString *stringb = @"huhu";
    BOOL result = [stringa compare:stringb] == NSOrderedSame;

    And print it out like this:
    NSLog(@"[@\"%@\" compare:@\"%@\"] == NSOrderedSame is %@ ",
    stringa, stringb, result ? @"yes":@"no");

    Then we get:
    [@"huhu" compare:@"huhu"] == NSOrderedSame is yes
    If we call instead
    stringb = @"not huhu";
    result = [stringa compare:stringb] == NSOrderedSame;

    We will get:
    [@"huhu" compare:@"not huhu"] == NSOrderedSame is no
    Of course, nobody warns us when we use a nil pointer instead:
    stringa = nil;
    result = [stringa compare:stringb] == NSOrderedSame;

    Which of course results to:
    [(null) compare:@"not huhu"] == NSOrderedSame is yes
    Luckily, writing the code this way:
    result = [stringb compare:stringa] == NSOrderedSame;
    Results in the correct value again:
    [not huhu compare:@"(null)"] == NSOrderedSame is no

    Learnings?
    So we learned: We need to check the left object, the method receiver, for not being nil to prevent strange results. And in cases, where we compare against a constant object, we might as well put the constant on the left hand side, resulting in e.g.
    result = [@"huhu" compare:objectb] == NSOrderedSame;
    to prevent stumbling over nil pointers.