How to check for null value in NSNumber
Asked Answered
W

3

5

First off I confess my ignorance, I've learned everything I know about Objective-C in the few months I've been working on my project. I also find it utterly frustrating how Objective-C seems to complicate what would be simple matters in any other language I've worked with. This question is a case in point...

In the first run my app downloads a bunch of JSON which it uses to populate a CoreData store. I use an Obj-C/JSON library (CJSONDeserializer) to convert the JSON to NSArrays. In the JSON download for one CoreData entity there's a field containing a number ("show_id":2) identifying the related field in another entity if there is one or null ("show_id":null) otherwise. In processing that field I assign it to an NSNumber using...

NSNumber *shoIndex = [[item objectForKey:typeKey] objectForKey:@"show_id"];

I then try to check that I have a valid number before attempting to fetch & link the related record so as to not do wasteful processing where there is no related record.

Interrogating shoIndex with...

NSLog(@"shoIndex: %i, %@, %@", shoIndex, shoIndex, [shoIndex description]);

Gives...

shoIndex: 19590600, <null>, <null>

where the JSON value was null &...

shoIndex: 228300880, 51, 51

otherwise.

So far the only successful check I've made is with...

if (![[shoIndex description] isEqualToString:@"<null>"]) {

Can anyone suggest a better way?

Update...

Looking at it another way shoIndex is assigned as a NSNumber that sometimes contains a NSString value @"<null>". Does Obj-C have something like an isa operator that I could use to check the type of the contents of shoIndex?

TIA, Pedro.

Wellington answered 20/11, 2010 at 5:2 Comment(1)
What makes you think that the object is an instance of NSNumber?Boundless
R
11

Use [shoObject class] to get the class of an object; so, to test shoObject's class, you would use

[shoObject isKindOfClass:[NSString class]];

Once you've sorted out what markers define an empty string or NSNumber, you can create a macro. I do with this by keeping an IsEmpty macro in a file called CommonMacros.h. Here's the code:

//Thanks Wil
//http://wilshipley.com/blog/2005/10/pimp-my-code-interlude-free-code.html

static inline BOOL IsEmpty(id thing) {
    return thing == nil
    || ([thing isEqual:[NSNull null]]) //JS addition for coredata
    || ([thing respondsToSelector:@selector(length)]
        && [(NSData *)thing length] == 0)
    || ([thing respondsToSelector:@selector(count)]
        && [(NSArray *)thing count] == 0);
}

Then, after importing CommonMacros.h, you can call the function like this:

if (IsEmpty(shotIndex)) {
    //do stuff
}

This should take care of this problem, and will also work on strings, arrays, etc, as you can see from the code. Thanks to Wil Shipley!

Restraint answered 20/11, 2010 at 5:11 Comment(4)
Thanks Wil, that works a treat. Looking at the URL you gave there I think you've already helped me in other ways :)Wellington
I spoke too soon. I want to do stuff if shoIndex is not empty so I tried !IsEmpty(shoIndex) and my NSNumber flies straight though it.Wellington
Hmm, odd, that's too bad. I'll suggest adding this isEqualToString:@"<null>" test to the IsEmpty code, but of course dodging that route is the reason you asked this question in the first place.Restraint
I've done that but agree that it's just moving what I wanted to dodge.Wellington
L
0

In some cases, such as missing keys in NSUserDefaults, you get back the literal @"" as an empty string.

Here's my safe check for an NSNumber.

Note the check for it being an NSNumber occurs first because NSNumber doesn't understand isEqualToString

        id savedPin = [[NSUserDefaults standardUserDefaults] valueForKey:@"blah"];  // don't assume is created so don't type as NSNumber*
        if ( ![savedPin isKindOfClass:[NSNumber class]] && [savedPin isEqualToString:@""]) {  
Loudhailer answered 13/12, 2014 at 3:17 Comment(0)
Y
-1

In Objective-c, it's nil not null. So:

if (shotIndex != nil) {
   // its not nil
}
Yucca answered 20/11, 2010 at 5:6 Comment(2)
This is exactly what I first tried & it didn't work. Where you see <null> in my question that is what NSLog gives for the NSNumber where the JSON item was null.Wellington
This is JSON. If the shotIndex wasn't present in the JSON data, then it would be nil. However, as Pedro said, the shotIndex was present with a value of null, and JSON parsers will give you a value of [NSNull null], not nil. Sending most messages to [NSNull null] will crash, so this is an important difference.Minoru

© 2022 - 2024 — McMap. All rights reserved.