Testing for nil in addTask


#1

If I pressed the “Insert” button before doing anything else, the app would crash. Using the debugger I tracked to this line:

The issue was a nil value in t did not make the above code true and trigger the return.

Googling around I tried this, which seems to work:

// get the to-do item NSString *t = [taskField text]; // quit if there is no task to add // if ([t isEqualToString:@""]) { if ([t length] == 0) { // only this line was changed return; }

What’s the preferred way to check for nil values?
Why does [taskField Text] return nil at the start, but what I’m guessing is a valid string pointer later?


#2

The code is bugged - and it’s strange to test for string equality instead of just testing if the variable is nil. The correct code (and what you’ll usually see in safety checks like this) is:

if (variable) //only nil will be false, any non-nil value returns true
{
     //do something with arrays, etc. where you can't have a nil value
}

#3

Actually, I think James has the better solution. If you’re checking for an empty string, it’s always safe to compare the return value from length against 0, since it’s safe to invoke methods on nil, and in this context the “placeholder” value is 0.

I wrote a blog post about creating an Objective-C isNullOrEmpty method like C# has, but concluded calling length was perfectly reasonable.


#4

James’ solution is broader, and may be preferred, but it depends on the code. In this case there’s no difference between testing for nil and testing for “” because the original code doesn’t contain an alloc/init for the NSString (it’s just set from the button, which is obviously not good in the case of a blank entry). I can see three reasonable ways to fix this code:

  1. Alloc/init the NSString prior to assigning it the value from taskField - this ensures it won’t have a nil value, though it may have a value of “” (i.e. empty string), so the rest of the original code should be fine.

  2. Keep the code as is, but test for nil before adding to the array (you can’t add nil to an array). To me, this is a preferred solution because honestly, why wouldn’t you be paranoid about testing for nil before doing anything with arrays? That’s where the all the exceptions come from. I’d test for nil on a variable set from a method call even if I had previously initialized the variable, out of an abundance of caution.

  3. Test for length - a length of zero will return true both if the variable is nil or the string is empty. Yes, it’s more versatile that way, but it’s not always necessary to do a string comparison just to test for nil, and sometimes an empty string is allowable but nil obviously wouldn’t be.

So yeah, the very minimum safeguard is to test for nil before adding an object to an array, which is why I jumped there because it’s the lowest common denominator for safety - and nil is where the exceptions come from. But checking for empty strings can also be important in some programs, I can see. But you might want to allow empty placeholder strings to be added into an array for other programs, so it’s not always a preferred solution.


#5

Found the same issue. I’ve just added a

[taskField setText:@""]

after where the place holder for taskField is set, because only the first test crashes (taskField text is set to “” in addTask: after the test on the empty string so only the first initialization was missing).


#6

I’ve changed the addTask: this way, don’t really know which way is best though…

//quit here if taskField is empty if (!t || [t isEqualToString:@""]) { return; }