Kind of null variable IOS - ios

i am actually debugging my iOS Application: i want to test if a variable is null or not:
Stupid question huh !
if (var !=nil) { doSomeWork ; }
So if the variable var is equal to nil and we want to print this result in the debugger area we will have something like that:
2012-10-12 21:33:01.553 Application's Name [892:13d03] (null)
This is cool, but indeed when i try to print the variable content in the debugger area, it has been showing :
2012-10-12 21:33:01.553 Application's Name [892:13d03] < null >
Can you tell me guys what is the difference between this two kinds of null, and how can i test if the second one is equal to nil.
Thanks in advance

The second output, <null>, comes from the NSNull singleton. This is a class called NSNull that has a class method +null that returns the same singleton instance of NSNull every time. The primary purpose of this class it to be able to act as a stand-in for nil in places where you can't put nil, such as in collections. For example, JSON libraries typically return NSNull when the JSON includes null.
You can test for this simply by asking if it's == to [NSNull null] (since it's a singleton), or possibly if [obj isKindOfClass:[NSNull null]]. You could use [obj isEqual:[NSNull null]] if you like. You could even ask if it's == kCFNull if you want, since CFNull and NSNull are toll-free bridged. Whatever style you want is up to you.

NSNull it is class, nil is not. So if you are comparing nil with something you should use "==", if NSNull then -> if ([var isEqual:[NSNull null]]) { ....}

Related

iOS: Is this a good way to check if JSON dictionary object is an NSString?

I want to check if a JSON object is an NSString and if it isn't, assign it a default string. My ultimate goal is to prevent crashing and assign the properties a proper value no matter what. This is an example of a data model I am using where dict is the JSON dictionary the API returns.
Data *data = [[self alloc] init];
data.name = [NSString validateString:dict[#"name"] defaultString:#""];
data.status = [NSString validateString:dict[#"status"] defaultString:#"OPEN"];
Here is the category method validateString I am using.
+ (NSString *)validateString:(NSString *)aString defaultString:(NSString *)defaultString {
if ([aString isKindOfClass:[NSString class]]) {
return aString;
}
return defaultString;
}
It makes no sense, and is very bad practice, to cast (NSString *)aString and then ask if this is in fact an NSString.
Also, what if it is nil?
All you know when you fetch from a dictionary is that you get an id. Do not assume more than that.
I would suggest writing very plainly: say what you mean, and mean what you say. That is the best practice in Objective-C. Otherwise, dynamic typing and "nil trickery" can lead you into subtle errors. You might not have any trouble in this particular case, but bad habits are bad habits, and it is best not to let them form in the first place. I'd rewrite like this:
+ (NSString *) checkType:(nullable id)obj defaultString:(NSString *)def {
if (obj == nil || ![obj isKindOfClass:[NSString class]]) {
return def;
}
return obj;
}
Like mentioned in other comments: if you want to prevent crashes, you also need to check if it's nil, specially if there is a chance to port your code to Swift in the future.
Just to clarify my last sentence, the line below works in Objective-C even if aString is nil:
if ([aString isKindOfClass:[NSString class]]) {
That's because, in the way Objective-C was made, calling a function on a nil object returns nil, so the if will be considered false, and the function will return defaultString. Yeah... that's certainly a bad idea when they created Objetive-C, since this leads to lots of errors. More details about that behaviour below:
https://stackoverflow.com/a/2696909
Anyway, it's also a good practice to only cast an object after checking its type, so I would recommend adapting your function to this:
+ (NSString *)validateString:(id)obj defaultString:(NSString *)defaultString {
if (obj != nil && [obj isKindOfClass:[NSString class]]) {
return (NSString*)obj;
}
return defaultString;
}
Every object that implements NSObject* has isKindOfClass: (and NSDictionary* only stores objects that implement NSObject*), so we don't need to check if the object responds to it. Also, even if we wanted, respondsToSelector: is also an NSObject* function.
Still, the method that you are using still works. The revised function above is just adapted to better practices and to avoid problems in case you ever need to port this code to Swift (or any other language) in the future.
EDIT: Updated code based in #matt's suggestion.

Objective C syntax issue related to parameter not getting right data

I've been working on a project implementing Hola CDN framework. I'm now running into an issue that I can't pass on current date to the parameter programDay and I traced the source code and I found the below line. What does this below line mean?
self.programDay = ![dict[GETPROGRAMLISTDATA_PROGRAMEDAY] isEqual:[NSNull null]] ? dict[GETPROGRAMLISTDATA_PROGRAMEDAY] : nil;
What's NSNull
[NSNull null] doesn't equal to nil. It means empty value. For example,
#[[NSNull null]].count equals to 1. NSNull is used as placeholder in NSArray and NSDictionary. It means nil.
For your question
This line is used to replace NSNull with nil.
self.programDay = ![dict[GETPROGRAMLISTDATA_PROGRAMEDAY] isEqual:[NSNull null]] ? dict[GETPROGRAMLISTDATA_PROGRAMEDAY] : nil;
This line means that if [dict[GETPROGRAMLISTDATA_PROGRAMEDAY] has empty value or null value the nil would be assign to self.programDay as there would be value of [dict[GETPROGRAMLISTDATA_PROGRAMEDAY] will be assign to self.programDay. Usually (null) value is return from webservice if that value is not presented in database on server.

How to handle NSNull values

In Objective C, a common practice is to often forgo checking for nil, instead relying on the fact that messaging nil silently fails.
For example, to validate a string:
if ([myString length] > 1) { // Short and sweet
If myString is nil, this check will fail - as intended. It's a huge improvement over what one may assume would be the correct implementation, explicitly checking for nil:
if (myString && [myString length] > 1) { // Redundant nil check
However, particularly in the case of a web API, myString could conceivable equal [NSNull null] - similar to nil, but with different behavior. Of primary concern, is that messaging NSNull causes an exception. For example, our short simple solution from earlier will cause an exception:
// Causes an exception, because [NSNull null] is an object
NSString *myString = (id)[NSNull null];
if ([myString length] > 1) {
To further complicate things, a simple nil check will actually pass because [NSNull null] is a valid object:
NSString *myString = (id)[NSNull null];
if (myString) { // Evals to YES
So, the only way to be completely safe is to both check for NSNull and do your regular implicit nil check, by calling a method:
if (myString != (id)[NSNull null] && [myString length] > 1) { // Short and sweet
My Question: is this really necessary? Is there a more concise option with less duplicate code, that I've overlooked? Are my conclusions, in fact, correct?
NSNull objects typically crop up with people reading JSON files containing null values.
In that case, there is a chance that the server that supplied the null value thinks you should do something different than with no value. For example, if you get a dictionary and there might be a string stored under some key, you might get a string with non-zero length, you might get an empty string because the server sent you an empty string, you might get nothing because the server sent you nothing, or you might get [NSNull null] because the server sent you a null value. Up to you to decide if the empty string, nothing, and [NSNull null] need to be treated differently or not.
By the way: I have always used some extensions to the NSDictionary class, for example - (NSString*)stringForKey, which will return either an NSString or nil, 100% guaranteed. If you do that, all your error checking is in one method. And you can do things like converting NSNumber to NSString, or NSNull to nil, or NSDictionary etc. to nil, and never worry about it again. Of course you need to check if it is appropriate.
is this really necessary?
If some API can return NSNull instead of a string, then yes, you should check for it. It's usually not necessary since NSNull is not a string and won't be returned by most methods that would return a string. But a collection such as a dictionary, for example, can have any object as a value. If you're not sure that the value will be a string, you should take appropriate precautions.
Is there a better way to handle the possibility of NSNull that I've overlooked?
Another way that you could do roughly the same thing but protect yourself from other types (NSNumber, for example) is to check the type of the thing that you get back rather than comparing specifically against [NSNull null]:
if ([myString isKindOfClass:[NSString class]] && [myString length] > 1) { //...
In addition to the other answers, you could consider replacing NSNull instances with empty strings before parsing your API response into model objects. Similarly, you could traverse a mutable copy of the response dictionary and remove keys whose values contain NSNull.
Basically, do it up front when you get the response so that your code isn't littered with NSNull checks.
Another way to approach this is to use a Category:
#interface NSNull (Utilities)
- (NSString *)stringValue;
#end
#implementation NSNull (Utilities)
- (NSString *)stringValue
{
return nil;
}
#end
And then simply:
[myDictionary[#"key"] stringValue] // returns nil for NSNull values

Checking if a key in standardUserDefaults has been set or is NSNull

What is the correct way to check the contents of standardUserDefaults ?
If I print out what is stored in a key i get:
NSLog(#"logged_in_status : %#", [standardUserDefaults stringForKey:#"logged_in_status"]);
Output: logged_in_status : (null)
So it seems to be NSNull.
So I will add a check for that as follows:
if ([[standardUserDefaults objectForKey:#"logged_in_status"] isKindOfClass:[NSNull class]])
{
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
Output: NO
Why does this not resolve to the YES? Isn't it an NSNull?
I've been looking at this for a long time and can't see where the error is.
Could anybody kindly explain where I've gone wrong on this?
Thanks,
Code
When you do the key lookup initially, you're not getting back an instance of NSNull, but instead no result at all: in other words, nil, which isn't the same thing as NSNull. That typically means that no value has been set for that key in the user defaults yet. (You can see this if you look at it under the debugger while stepping through-- the "stringified" version of nil happens to be "(null)" when you print it to the log, which is partly what I think may be confusing here.)
(If this distinction is fuzzy for you, have a look at the answer to this question about the differences between the various forms of "null" you might encounter: What are the differences between nil, NULL and [NSNULL nil]?)
As #Francescu suggests in a comment, if you're trying to do a check for "has this value ever been set", it could look something like:
NSString * loggedInStatus = [standardUserDefaults stringForKey:#"logged_in_status"];
if (!loggedInStatus) {
NSLog(#"status not set");
} else {
NSLog(#"status: %#", loggedInStatus);
}
Just some additional info to the other answers: when you format a string including the %# format specifier, a nil value will format as "(null)" with parentheses. An instance of NSNull — the instance, since it's a singleton — formats as "<null>" with angle brackets.

How can I check for an empty object within an NSArray

I'd like to check for an empty object (i.e. an object of an array which doesn't have a value) within an array which gets its data from a file.
As an example, if my array contains 12 objects (all NSString) and the object at index 11 doesn't return a value when its description is printed into the debug section of Xcode. I want to check if that is the case and respond accordingly. I already tried
if (!([MY_ARRAY objectAtIndex:11] == nil))
{
//Some Stuff
}
else
{
//Some other Stuff
}
which didn't work.
Any help is appreciated.
The description method is for debugging. You should not use it in your program logic. What are these objects, and what do they contain? Can you modify the objects to add an "isEmpty" property?
If you use NSNull, you'd use code like this:
NSArray *array = #{#"String", #(4), [NSNull null], #"Another string");
for (id anObject in array)
{
if (anObject =! [NSNull null]))
{
//Some Stuff
}
else
{
//Some other Stuff
}
}
You can check the length of the string: [string length] > 0
an object is an array cannot be nil, but you can use [NSNull null] which is an "object equivalent" to nil
As Jerome Diaz states, objects in an array can't be nil. The only option you have is to check the count property of the array if it reflects an expected value, or you can inspect the type/class of the object in the array. A safe way to include empty object into array is [NSNull null], but this is the task for the method that fills the array, not the one that reads it.
You can check the class type of an object in array with isKindOfClass or isMemberOfClass.

Resources