Detect if NSNumber is zero, nil or 0 - objective-c

I have a variable in core data. I want to detect for the cases where it is nil zero, null or otherwise does not have a nice value such as 222 or 333.
This should be trivial but I am getting caught up in Objective-C's syntax.
Following code is not working:
if (_item.id!=nil && _item.id!=0) {
//do something
}
Of note id should be an NSNumber.
It is defined as
#property (nonatomic, retain) NSNumber * id;
I should clarify that it is not working when the value logs to console as 0.
Given the way variable types and core data work, I cannot tell you what causes the variable to log to console as '0' but something is causing it to do so. Basically, I want to exclude cases where the value is anything other than a non-zero integer (in mathematical, not computer science terms).

To check the numeric value stored in an NSNumber, you have to call one of the methods which give you a primitive type.
e.g. integerValue, unsignedLongLongValue, doubleValue
To correctly check for nil and a value of 0, you need the following:
if (_item.id != nil && [_item.id intValue] != 0) {
// code here
}
Because sending a message to a nil reference returns 0, you can take a shortcut:
if ([_item.id intValue] != 0) ...
This works because _item.id has to be non-nil to return a non-zero value from intValue.

As this NSManagedObject is of type NSNumber, simply check the intValue.
if (!_item.id.intValue){
//Method will stop in here if the id is nil/0 etc.
}
However, it is not recommended to name a variable id, I suggest you rename it to itemId
In the same way you shouldn't name something 'string', or 'new' etc as these conflict with Apple's own native naming policies

To check the numeric value stored in an NSNumber, you have to call one of the methods which give you a primitive type.
e.g. integerValue, unsignedLongLongValue, doubleValue
To correctly check for nil and a value of 0, you need the following:
if (_item.id != nil && [_item.id intValue] != 0) {
// code here
}
Because sending a message to a nil reference returns 0, you can take a shortcut:
if ([_item.id intValue] != 0)

Related

Does using compare on a nil NSNumber always return NSOrderedSame?

NSNumber *badNum = 0;
NSNumber *goodNum = #42;
if ([badNum compare:goodNum] == NSOrderedAscending)
// ...
Given the above snippet, where badNum is effectively nil, is the if statement guaranteed to never be entered?
Essentially, I want to know if I must do a nil check every time I use -[NSNumber compare:], so another question is will I need to use the following code to make sure compare always works as it appears?
if (badNum && goodNum && [badNum compare:goodNum] == NSOrderedAscending)
// ...
Yes, it is guaranteed, as long as Apple does not change NSOrderedSame, which is currently defined as zero:
enum {
NSOrderedAscending = -1,
NSOrderedSame, // == 0
NSOrderedDescending // == 1
};
The reason you appear to get NSOrderedSame when sending compare: message to nil is that Objective-C supplies the default value for the return type when the target is nil. Since NSOrderedSame is 0, the default value, you are guaranteed to get it when badNum is nil.

How do I test for null in NSDictionary from SBJSON?

I've got an API returning a JSON encoded string of data that returns a real number or "null" as a value. As long as the JSON contains a numeric or string value, everything works as expected. If the key:value pair value is null, the code below crashes.
How do I properly test NSDictionary objectForKey when it's getting a NULL from SBJSON?
When the API returns a null for filetype, the code below crashes at the if() line.
My Objective-C code attempts to test for expected values:
if (1 == [[task valueForKey:#"filetype"] integerValue]) {
// do something
} else {
// do something else
}
The API JSON output:
{"tclid":"3","filename":null,"filetype":null}
The NSLog() output of the NSDictionary is:
task {
filename = "<null>";
filetype = "<null>";
tclid = 3;
}
When transferring data from JSON to a Cocoa collection, the NSNull class is used to represent "no value", since Cocoa collections can't have empty slots. <null> is how NSNull prints itself.
To test for this, you can use someObject == [NSNull null]. It's a singleton -- there's only one instance of NSNull per process -- so pointer comparison works, although you may prefer to follow the usual Cocoa comparison convention and use [someObject isKindOfClass:[NSNull class]].
You're getting the crash because you're sending integerValue to that NSNull object. NSNull doesn't respond to integerValue and raises an exception.
You should first test if there is a value is null, if it is null performing the intValue method may crash your application.
Doing this should do.
if ([[task valueForKey:#"filetype"] isKindOfClass:[NSNumber Class]] && 1 == [[task valueForKey:#"filetype"] integerValue]) {
// do something
} else {
// do something else
}
I hope it helps.

How to check that float property of managed object is nil?

Score is NSManagedObject. score.latitude is an NSNumber, which actually is a float value.
NSLog(#"%f", [score.latitude floatValue]);
shows 0.000000.
Construction I use to check for nil:
if (score.latitude == nil)
doesn't work.
It's irrelevant that there is a floating-point value stored in your NSNumber instance; the object itself is either nil or not. To check for an object being nil, if( obj == nil ) is functionally equivalent to if( obj ).
So your conditional may not be doing what you expect, but it is checking for nil. You'd need to add more details about what's happening in the body of the if, should you need more specific explanation.
The key point is that sending a message to nil, such as [nil floatValue] always returns 0, interpreted as whatever the return type of the method is. For example, if you send floatValue to nil, you'll get back floating-point 0. If you send a message that should return an object, you'll get nil; a message that should return an int, you get integer 0.
Also be aware that when you say if( score.latitude ), the expression will evaluate false if either score or latitude is nil (because if score is nil, sending latitude to it will return nil.)
A float can be nil, as it isn't an object.
And a NSNumber is not an float value, but has a method, that returns a float value.
use if (score) to check, if the NSNumber got instantiated before.
As I finally understand, the problem is because of Core Data save data to sql database, which stores nil properties as 0.000...

id dynamic type documentation

Can someone point me to the specific "id type documentation" ? I've been through the dynamic typing docs, but I want to know how to use the type id. Specifically how to check if id is null.
The id type is directly related to the Objective-C language itself, rather than the Cocoa/Cocoa Touch frameworks as your original tags implied. There is also no dynamic typing involved. Here's a little introduction in Apple's docs.
To answer your specific question, quoted from the above link:
The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.
nil and NULL are equivalent (zero pointers), and therefore interchangeable.
In a basic if statement, you just do this:
id myId = [[something alloc] init];
// Short for if (myId == nil)
if (!myId) {
// myId is nil
} else {
// myId is not nil
}
See The Objective-C Programming Language — specifically, the chapter on Objects, Classes and Messaging.
In Objective-C, object identifiers are of a distinct data type: id. This type is the general type for any kind of object regardless of class and can be used for instances of a class and for class objects themselves. […]
The keyword nil is defined as a null object, an id with a value of 0. id, nil, and the other basic types of Objective-C are defined in the header file objc/objc.h.
To compare variables by value, you simply use the == operator. So to test for nil, you do:
someVariable == nil
I've not seen it clearly stated in any other answers so I'll say it here:
an id is defined as a pointer to an object.
nil is zero cast as an id - (id)0 - as a result the following code:
NSString * myString = nil;
id idString = myString;
if (idString == nil) NSLog(#"idString == nil");
if (idString == NULL) NSLog(#"idString == NULL");
if (idString == (id)0) NSLog(#"idString == (id)0");
will have the following output:
2011-09-12 07:25:57.297 Sample Project[22130:707] idString == nil
2011-09-12 07:25:57.298 Sample Project[22130:707] idString == NULL
2011-09-12 07:25:57.299 Sample Project[22130:707] idString == (id)0
Sorry if I misunderstood your question, but wouldn't you just do something like:
// given
id sender;
if (sender == nil) {}
Basically you use id to catch any object that might be assigned to it. So you can do something like:
id name = [NSString stringWithString:#"john"];
and now name will be an NSString object, which you can verify by calling [name class].
Take a look at the id section of this page for more information.

Best way to implement a true/false/undefined trichotomy variable in objective-c

I'm temped to use an int, and make 0 == NO, 1 == YES, and anything else == undefined.
Obviously there are a million ways to do something like this, but what seems like the best way to you? Concerns I can think of include simplicity and memory footprint (e.g. what if I have a lot of these?).
Another way is to use two BOOLs, one for isDefined, and one for value
Another way,
typedef enum { CPStatusUndefined, CPStatusAvailable, CPStatusUnavailable } CPStatus;
Edit, the use case is:
I have a yes/no property that is difficult to calculate. When it is being checked, it is checked frequently (by UIMenuController, OFTEN), but unless the user selects it, it is never checked. The way I chose to deal with this is a tri-type variable. The first time you check, if it is undefined you calculate the yes/no value and return it, after that you just return the yes/no value.
Use an enum. In Objective-C they work just like they do in C/C++
typedef enum {
No = 0,
Yes,
Other
} tri_type;
tri_type myVar = No;
if( myVar == Yes || myVar == Other ) {
// whatever
}
How about NSNumber, since it can be nil?
[number boolValue] == YES;
[number boolValue] == NO;
[number boolValue] == nil; // or just number == nil
If you want to conserve the most amount of memory, use a char.
char == 0, false
char == 1, true
else, undefined.
Obviously, you'll want to initialize it at something like -1.
This is the way obj-c does comparator return values:
if 0, they are equal.
if positive, a > b
if negative, a < b
Same idea as above.