I have a piece of code that detects if a NSString
is NULL
, nil
, etc. However, it crashes. Here is my code:
NSArray *resultstwo = [database executeQuery:@"SELECT * FROM processes WHERE ready='yes' LIMIT 0,1"];
for (NSDictionary *rowtwo in resultstwo) {
NSString *getCaption = [rowtwo valueForKey:@"caption"];
if (getCaption == NULL) {
theCaption = @"Photo uploaded...";
} else if (getCaption == nil) {
theCaption = @"Photo uploaded...";
} else if ([getCaption isEqualToString:@""]) {
theCaption = @"Photo uploaded...";
} else if ([getCaption isEqualToString:@" "]) {
theCaption = @"Photo uploaded...";
}
}
And here's the error:
Terminating app due to uncaught exception 'NSInvalidArgumentException
', reason: '-[NSNull isEqualToString:]
: unrecognized selector sent to instance 0x3eba63d4
'
Am I doing something wrong? Do I need to do it a different way?
The NULL
value for Objective-C objects (type id
) is nil
.
While NULL
is used for C pointers (type void *
).
(In the end both end up holding the same value (0x0
). They differ in type however.)
In Objective-C:
nil
(all lower-case) is a null
pointer to an Objective-C object.
Nil
(capitalized) is a null pointer
to an Objective-C class.
NULL
(all caps) is a null pointer to
anything else (C pointers, that is).
[NSNull null]
is a singleton for situations where use of nil is not possible (adding/receiving nil to/from NSArray
s e.g.)
In Objective-C++:
- All of the above, plus:
null
(lowercase) or nullptr
(C++11 or later) is a null pointer to C++ objects.
So to check against nil
you should either compare against nil
(or NULL
respectively) explicitly:
if (getCaption == nil) ...
or let ObjC / C do it implicitly for you:
if (!getCaption) ...
This works as every expression in C (and with Objective-C being a superset thereof) has an implicit boolean value:
expression != 0x0 => true
expression == 0x0 => false
Now when checking for NSNull
this obviously wouldn't work as [NSNull null]
returns a pointer to a singleton instance of NSNull
, and not nil
, and therefore it is not equal to 0x0
.
So to check against NSNull
one can either use:
if ((NSNull *)getCaption == [NSNull null]) ...
or (preferred, see comments):
if ([getCaption isKindOfClass:[NSNull class]]) ...
Keep in mind that the latter (utilising a message call) will return false
if getCaption
happens to be nil
, which, while formally correct, might not be what you expect/want.
Hence if one (for whatever reason) needed to check against both nil
/NULL
and NSNull
, one would have to combine those two checks:
if (!getCaption || [getCaption isKindOfClass:[NSNull class]]) ...
For help on forming equivalent positive checks see De Morgan's laws and boolean negation.
Edit: NSHipster.com just published a great article on the subtle differences between nil, null, etc.
You should use
if ([myNSString isEqual:[NSNull null]])
This will check if object myNSString is equal to NSNull object.
Preferred Way to check for the NSNULL
is
if(!getCaption || [getCaption isKindOfClass:[NSNull class]])
if([getCaption class] == [NSNull class])
...
You can also do
if([getCaption isKindOfClass:[NSNull class]])
...
if you want to be future proof against new subclasses of NSNull.
Just check with this code:
NSString *object;
if(object == nil)
This should work.