3

I have a method where I want to make sure I do something special when I encounter an "empty" string. It works great when it actually has a string, or when I specifically set it to "nil" or "NULL", but it crashes when I try to test an uninitialized NSString. How do I handle that scenario?

For example:

-(void) WhyDoICrash
{
  NSString *foo;

  // Some other stuff...

  // foo should be considered "empty"
  if (foo == nil || foo == NULL || [foo length] == 0)
  {
    // whatever
  }
}

============= EDIT ===================

Ok, the above was just a REALLY simple example that displays the problem. I'm actually using a category for NSString, which means some of the (good, but not applicable) suggestion I'm getting can't be used. Here is my exact code:

#pragma mark - NSString Category

@interface NSString (NullOrEmptyTesting)
+(BOOL) isNullOrEmpty: (NSString*)input;
@end

@implementation NSString (NullOrEmptyTesting)

+(BOOL) isNullOrEmpty: (NSString*)input
{
  return (input == (id)[NSNull null] || input.length == 0);
}

@end
ghostatron
  • 2,620
  • 23
  • 27

2 Answers2

5

(…) but it crashes when I try to test an uninitialized NSString. How do I handle that scenario?

You handle it by initialising the corresponding variable, e.g.

NSString *foo = nil;

In both C and Objective-C, automatic variables are not initialised with 0 — you cannot make any assumption about the value contained in that variable. See this question: What happens to a declared, uninitialized variable in C? Does it have a value?

Also,

if (foo == nil || foo == NULL || [foo length] == 0)

is equivalent to:

if (foo == nil || [foo length] == 0)

and, since Objective-C supports messaging nil objects, it’s common to test:

if ([foo length] == 0)

only.

Note that Objective-C does initialise instance variables with 0 when an instance is allocated, though.

Community
  • 1
  • 1
  • I agree with what you are saying. My real-life scenario is actually a method that takes the string as a parameter. I just wanted to give a code sample that was really simple that shows the problem. :-) – ghostatron Oct 15 '11 at 01:14
  • @con And what is the method argument? If it comes from an uninitialised automatic variable then it’s the same reasoning: you cannot make any assumption about its value. –  Oct 15 '11 at 01:21
  • I just edited the original post to give the exact code. I'm adding a category to NSString, and if I use the method with an uninitialized variable, it crashes. -.- – ghostatron Oct 15 '11 at 01:29
  • 1
    @con As I said, you _cannot_ make any assumption about uninitialised automatic variables. This means you _cannot_ test whether an automatic variable, or a parameter whose argument comes from an automatic variable, has been initialised or not. –  Oct 15 '11 at 01:34
  • Does that mean my only option for that case is a try/catch block? – ghostatron Oct 15 '11 at 01:37
  • @con try/catch won’t help you because EXC_BAD_ACCESS isn’t a regular Objective-C exception. Your code must make sure that all automatic variables are initialised before they are read. –  Oct 15 '11 at 01:41
  • So it sounds like I'm screwed b/c I NEED to catch that scenario. I will give you credit for the answer since you explain WHY I am screwed. ;-) – ghostatron Oct 15 '11 at 01:47
  • @con Why do you need to catch that scenario? If it’s for debugging purposes, using a static analyser or zombies should help. –  Oct 15 '11 at 01:54
  • My code is in a framework that is used by any number of in-house apps being built here. When people send a string like that to one of my methods, it goes belly up. Am I just being too nurturing towards those other devs? Is it their problem, not mine? – ghostatron Oct 15 '11 at 01:59
  • @con It’s definitely their problem. Tell them about Clang Static Analyser and zombies. :) –  Oct 15 '11 at 02:03
0

You wouldn't be crashing if you were doing an AND comparison.

i.e.

if ((foo != nil) && (foo != NULL) && ([foo length] > 0))
{
    // do something
}

The reason you're crashing is that the OR comparisons you're doing evaluate everything (including [foo length], every time). You're sending a message to an invalid object in that case, hence the crash.

When doing an AND comparison. A successful "foo == NULL" test would stop evaluating everything else (so you wouldn't go into -- and crash in -- [foo length])

Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • It does still crash actually (with the latest xCode 4.2 and sdk 5). It is not recognizing that foo as nil or null, so it is evaluating the [foo length] part. – ghostatron Oct 15 '11 at 01:17
  • As a side note, I always thought c would ALWAYS short circuit once it determines an "IF" statement is true or false. So in my case, it should see that foo is nil and recognize that no matter what the rest is, the statement is true and just stop. – ghostatron Oct 15 '11 at 01:19
  • 1
    You’ve negated the original condition so your answer does not represent the code in the original question. Also, if `foo` hasn’t been initialised and it happens to contain a value different from 0, your code will (in the vast majority of cases) crash as well. Furthermore, both `&&` and `||` are short-circuited in C and Objective-C. –  Oct 15 '11 at 01:23