8

I am beginning to find my code littered with:

if([p objectForKey@"somekey"] != [NSNull null]) {

}

Is there shorter (character-wise) comparison for NULL?

Background: I am using the SBJson library to parse a JSON string and there are often null values (by design) for some of the keys.

Adam Jenkins
  • 51,445
  • 11
  • 72
  • 100
  • The objectForKey method does not return [NSNull null]. It returns nil. – jarmod Jun 07 '13 at 17:17
  • This could give you a false positive. If `[p objectForKey:@"someKey"] returns `nil`, your test will pass. – Mike D Jun 07 '13 at 17:17
  • 1
    It returns `[NSNull null]` if that's what's in the dictionary. – Rob Napier Jun 07 '13 at 17:17
  • 1
    @jarmod Unless the object stored for `@"someKey"` is `NSNull`. – Mike D Jun 07 '13 at 17:18
  • See http://stackoverflow.com/questions/836601/whats-the-difference-between-nsnull-null-and-nil for the distinction. – jarmod Jun 07 '13 at 17:18
  • Yeah, good points about actually storing [NSNull null] in the dictionary. Thanks for the correction. – jarmod Jun 07 '13 at 17:20
  • 1
    There seems to be confusion here about the OP's question. Read the "Background." He's asking what he means to ask. – Rob Napier Jun 07 '13 at 17:20
  • 2
    I'd like to reopen this question. It is not a duplicate. The question is not how NSNull differs from nil, but programmer-efficient ways to test for NSNull. – Rob Napier Jun 07 '13 at 20:29
  • @RobNapier You are indeed correct and your answer is more inline with the actual question. I read the question rather quickly and since he is checking for NSNull *incorrectly* my answer was in respons to that issue. – Groot Jun 08 '13 at 22:25

7 Answers7

7

Nothing built-in, but it would be reasonable and simple to create a function MYIsNull() that would do the comparison you want. Just think through what you want to return in the case that the key is missing.

You may want to go the other way and transform -null into nil. For instance, you could add a category on NSDictionary like this:

- (id)my_nonNullObjectForKey:(NSString *)key {
   id value = [self objectForKey:key];
   if ([value isEqual:[NSNull null]) {
     return nil;
   }
   return value;
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • I like this solution. We Objective-C programmers are much more used to dealing with `nil`, and being able to use our usual patterns like `if (!myString) ...` is a big plus. – bdesham Jun 07 '13 at 17:28
  • 4
    Prefix that method, please, if you add it as a category on `NSDictionary`. – bbum Jun 07 '13 at 17:30
  • 1
    (For those following along at home, read "Avoid Category Method Name Clashes" at http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/ProgrammingWithObjectiveC/CustomizingExistingClasses/CustomizingExistingClasses.html. It really does matter, and it really has blown up quite badly in my face.) – Rob Napier Jun 07 '13 at 17:36
5

I would use

if([[p objectForKey@"somekey"] isEqual:[NSNull null]] || ![p objectForKey@"somekey"]) {
    // NSNull or nil
} else {
    // Stuff exists...Hurray!
}

It seem to work since [NSNull null] is in fact an "object". Hope it helps!

Daniel
  • 23,129
  • 12
  • 109
  • 154
Groot
  • 13,943
  • 6
  • 61
  • 72
3

No, you have to test for NSNull. However, if you're finding your code is being littered by it, you might want to create a #define for it.

Bear in mind also that if p is nil, or if p doesn't have a value for someKey, then [p objectForKey@"somekey"] != [NSNull null] evaluates to YES.

So you probably want something like this:

#define IsTruthy(X) ( X && (X != [NSNull null]) )
Simon
  • 25,468
  • 44
  • 152
  • 266
1

Is there shorter (character-wise) comparison for NULL?

[NSNull null] is 13 chars. You can say:

NSNull.null // << 11
(id)kCFNull // << 11

Or make a function:

IsNSNull([p objectForKey@"somekey"]) // << 10 in this case and requires no ==, !=

Or (cringes) use a category:

[p objectForKey@"somekey"].mon_isNSNull // << 13 in this case, but requires no ==, !=

Just be careful how you name that category when dealing with nil receivers.

justin
  • 104,054
  • 14
  • 179
  • 226
0

Since you are using SBJSON, you can easily change its code - you have the source.

I have actually modified SBJSON parser to skip [NSNull null] values. They are not added to the dictionaries and when I call objectForKey:, I never get [NSNull null], I just get nil. Then, in most situation I don't even have to check if the value is nil since calling a method on nil usually gives the result I expect.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
0

If you're just worried about the amount of time your taking to type, consider macros:

#define ISNULL(key) [p objectForKey:key] == [NSNull null]

then

if (!ISNULL(@"somekey")) ...
James Webster
  • 31,873
  • 11
  • 70
  • 114
-4

Pretty sure you can just say

if ([p objectForKey:@"somekey"]) {

}

I don't use NSNull much so I'm not 100% sure but I think it tests as false and any other object tests as true.

morningstar
  • 8,952
  • 6
  • 31
  • 42
  • 4
    If the value for 'someKey' is in fact `NSNull`, this test will pass. This if statement is equivelent to `if ([p objectForKey:@"someKey"] == nil )` – Mike D Jun 07 '13 at 17:13
  • 1
    I downvoted because I'm pretty sure this is incorrect. Could you please test it to be sure? – bdesham Jun 07 '13 at 17:13