How do I check if a NSNumber object is nil or empty?
OK nil is easy:
NSNumber *myNumber;
if (myNumber == nil)
doSomething
But if the object has been created, but there is no value in it because an assignment failed, how can I check this? Use something like this?
if ([myNumber intValue]==0)
doSomething
Is there a general method for testing objects on emptiness like for NSString available (see this post)?
Example 1
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSNumber *emptyNumber = [dict objectForKey:@"emptyValue"];
Which value does emptyNumber
contain? How can I check if emptyNumber
is empty?
Example 2
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSString *myString = [dict objectForKey:@"emptyValue"];
if (myString == nil || [myString length] == 0)
// got an empty value
NSNumber *emptyNumber=nil;
What happens if I use this after emptyNumber
was set to nil?
[emptyNumber intValue]
Do I get zero?
Example 3
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:@"" forKey:@"emptyValue"];
NSNumber *myEmptyValue = [dict objectForKey:@"emptyValue"];
if (myEmptyValue == nil)
// NSLog is never called
NSLog(@"It is empty!");
Like this way NSLog is never called. myEmptyValue
is not nil
and not NSNull
. So it contains an arbitrary number?
NSValue
, NSNumber
, ... are supposed to be created from a value and to always hold one. Testing for a specific value like 0
only works if it isn't in the range of valid values you are working with.
In the rare case where code is more straight-forward to work with if you have a value that represents "invalid" or "not set" and you can't use nil
(e.g. with the standard containers) you can use NSNull
instead.
In your first example this could be:
[dict setValue:[NSNull null] forKey:@"emptyValue"];
if ([dict objectForKey:@"emptyValue"] == [NSNull null]) {
// ...
}
But note that you can simply not insert (or remove) that value unless you need to differentiate nil
(i.e. not in the container) and, say, "invalid":
if ([dict objectForKey:@"nonExistent"] == nil) {
// ...
}
As for the second example, -intValue
gives you 0
- but simply because sending messages to nil
returns 0
. You could also get 0
e.g. for a NSNumber
whose intValue
was set to 0
before, which could be a valid value.
As i already wrote above, you can only do something like this if 0
is not a valid value for you. Note the for you, what works best completely depends on what your requirements are.
Let me try to summarize:
Option #1:
If you don't need all values from the numbers range, you could use one (0
or -1
or ...) and -intValue
/ ... to specifically represent "empty". This is apparently not the case for you.
Option #2:
You simply don't store or remove the values from the container if they are "empty":
// add if not empty:
[dict setObject:someNumber forKey:someKey];
// remove if empty:
[dict removeObjectForKey:someKey];
// retrieve number:
NSNumber *num = [dict objectForKey:someKey];
if (num == nil) {
// ... wasn't in dictionary, which represents empty
} else {
// ... not empty
}
This however means that there is no difference between keys that are empty and keys that never exist or are illegal.
Option #3:
In some rare cases its more convenient to keep all keys in the dictionary and represent "empty" with a different value. If you can't use one from the number range we have to put something differently in as NSNumber
doesn't have a concept of "empty". Cocoa already has NSNull
for such cases:
// set to number if not empty:
[dict setObject:someNumber forKey:someKey];
// set to NSNull if empty:
[dict setObject:[NSNull null] forKey:someKey];
// retrieve number:
id obj = [dict objectForKey:someKey];
if (obj == [NSNumber null]) {
// ... empty
} else {
// ... not empty
NSNumber *num = obj;
// ...
}
This option now allows you to differentiate between "empty", "not empty" and "not in the container" (e.g. illegal key).