Today I will describe some most common pitfalls in Objective-C that, a beginner developer can learn about and the advanced developer can refresh his information about it.

Ok, so without more time to introduce, let’s start.

#1 Pitfall – Overall traps

What can possibly go wrong with the below code?

CGFloat x = 0.25f;

if (-0.5f <= x <= 0.5f) {
    return 0;
}

So, minding that the compiler will evaluate this if statement to that:

CGFloat x = 0.25f;
if ((-0.5 <= x) <= 0.5) {
    return 0;
}

it won’t enter the if statement with x = 0.25 value. It’s because of the fact, that the comparison result is an Int, so it wil be 0 or 1. With value of x = 0.25; it will look like this:

if (1 <= 0.5) {
    return 0;
}

#2 Pitfall – Comparing Objects

In Objective-C we can compare objects in two ways:

  • compare by pointer
  • compare by value

Bearing that in mind, let’s take a look at below code example:

if (object == _storedObject) {
    NSLog(@"No need to replace stored Object!");
}

if ([object isEqual:_storedObject]) {
    NSLog(@"No need to replace stored Object!");
}

In the first if statement we are comparing the object and the _storedObject by pointers. If the pointers are equal, then the if statement will evaluate to true value.

In the second if statement we are comparing both objects by their internal values. Let’s assume that the object and the _storedObject are both NSString instances and they were assigned with the same string:

NSString *object = @"The same string";
_storedObject = @"The same string";

The compiler will compare those objects in the if statement by checking if those two objects contain the same values, in our case – the same strings.

#3 Pitfall – the nil value

When using objects we have to keep in mind, that the pointer that it is pointing to may be nil. Let’s have a look at the below method:

- (BOOL) processValueForKey:(NSString *)key {
    NSString *myString = _dictionary[key];

    // very long procedure
    myString = [myString MD5];
    ...
    return success;
}

What can possibly go wrong here?

Of course, it could be a situation when the dictionary does not contain such key, so it will return nil. With that nil value the whole long method will go further and take some time from the CPU. We can avoid such situation with creating an early return check, like this one:

- (BOOL) processValueForKey:(NSString *)key {
     NSString *myString = _dictionary[key];

     if (!myString) {
         assert(myString != nil); // or return NO;
     }

     // very long procedure
     myString = [myString MD5];
     ...
     return success;
}

#4 Pitfall – the nil comparisons

Imagine a code that tries to compare some objects and some of the variables are nil. Please look a minute at the example below:

[nil isEqual: @“string] // returns 0
[nil isEqual: nil] // returns 0
[@"string" isEqual: nil] // returns ?

When comparing a nil value to a valid object it is good that the first two examples will return 0. But how about the last one

[@"string" isEqual: nil]

It’s not clear how it will behave from a developers point of view. The isEqual: method is an Apple’s internal implementation, so it can throw an unhandled exception or it may crach or it may return simply 0. The message for that example is simple, when comparing objects like above, please DO CHECKS! :)

Ok, let’s take another example of nil comparisons. Please familiarize with a below code:

// From Apple Documentation - NSComparisonResult

enum {
 NSOrderedAscending = -1,
 NSOrderedSame,
 NSOrderedDescending 
};
typedef NSInteger NSComparisonResult;

// How about these?
[@"string" compare:@"string"]; // 1
[nil compare:@"string"];       // 2
[@"string" compare:nil];       // 3

Do you know already what are going to be the return values for the examples in 1., 2. and 3. line ? Look at the solution:

[@"string" compare:@"string"]; //returns 0 == NSOrderedSame
[nil compare:@"string"];       //returns 0 == NSOrderedSame
[@"string" compare:nil];       //returns 0 == NSOrderedSame

// WAT???

Yes, I know some of you may get frustrated, why this language accepts this? The answer is simple, there are cons and pros of such nil value architecture and sending messages to the objects. Yet, the solution is very simple: we have to do nil checks, because it’s not safe – the algorithm may behave unstable.