ios: Compare NSString to "<null>" not working - ios

I am consuming a web service that returns JSON. One of the values I get is "< null >".
When I run the follwoing code the if statment still get executed when it is not suppposed to.
Any reason why?
NSDictionary *location = [dictionary valueForKey:#"geoLocation"]; //get the product name
NSString *latitude = [location valueForKey:#"latitude"];
NSLog(#"%#", latitude);
NSString *longitude = [location valueForKey:#"longitude"];
if (![latitude isEqual: #"<null>"] && ![longitude isEqual: #"<null>"]) {
NSLog(#"%d", i);
CLLocationCoordinate2D coordinate;
coordinate.longitude = [latitude doubleValue];
coordinate.longitude = [longitude doubleValue];
[self buildMarketsList:coordinate title:title subtitle:nil]; //build the browse list product
}

I am consuming a web service that returns JSON. One of the values I get is "< null >"
Aha. Two possibilities:
I. The JSON doesn't contain latitude and longitude information. In this case, the keys for them aren't present in the dictionary you're getting back, so you are in fact obtaining a nil (or NULL) pointer. As messaging nil returns zero, both conditions will fire (due to the negation applied). Try this instead:
if (latitude != nil && longitude != nil)
and never rely on the description of an object.
II. Probably the JSON contains null values, and the JSON parser you're using turns null into [NSNull null], and in turn you're trying to compare a string against that NSNull. In this case, try this:
if (![latitude isEqual:[NSNull null]] && ![longitude isEqual:[NSNull null]])

I had same Problem, But solved as below,
Replace your if with following,
if (![latitude isKindOfClass:[NSNull class]] && ![longitude isKindOfClass:[NSNull class]])

if ([latitude isEqual:[NSNull null]])
{
//do something
latitude = #"";
}
else
{
//do something else
latitude = json value
}
This is what I will do. This is because I need to store the value even if a null return.

Typically if you get null in a JSON response, you'll need to check against NSNull.
In your case, you should do something like this:
if ( [location valueForKey:#"longitude"] == [NSNull null]) {
// is null object
}

Related

How to check if json object contains <null>?

I am getting a Json from server by making a network request in my app.I am getting <null> value for some keys in Json object.My app gets crashed if this type of response is received.Please tell me how can i validate>?
I have tried this but it does not work all time.
if(!(user_post.username==(id)[NSNull null]) )
{
user_post.username=[dict_user_info objectForKey:#"name"];
if(user_post.username!=nil)
{
ser_post.username=[dict_user_info objectForKey:#"name"];
}
else
{
user_post.username=#"Username";
}
}
Consider testing the value for null so your program won't crash. Like this:
if([dict_user_info objectForKey:#"name"] != [NSNull null])
{
ser_post.username=[dict_user_info objectForKey:#"name"];
}
Create a Category of NSDictionary and add following method in it, which replaces null value with empty string for each key in dictionary.
- (NSDictionary *)dictionaryByReplacingNullsWithStrings
{
const NSMutableDictionary *replaced = [self mutableCopy];
const id nul = [NSNull null];
const NSString *blank = #"";
for(NSString *key in self) {
const id object = [self objectForKey:key];
if(object == nul || object == NULL) {
//pointer comparison is way faster than -isKindOfClass:
//since [NSNull null] is a singleton, they'll all point to the same
//location in memory.
[replaced setObject:blank
forKey:key];
}
}
return [replaced copy];
}
Usage :
[yourJSONDictionary dictionaryByReplacingNullsWithStrings];
Read more about Category in iOS Tutorial 1 and Tutorial 2
yourJsonObject = [myDic valueforkey#"key"];
if(yourJsonObject != [NSNull null])
{
//not null
}
** you can also check whether object exist or not
if(yourJsonObject)
{
//exist
}
I think you've confused your logic. I am trying to stay true to your code, but let me know if the following is not what you intended:
if (dict_user_info[#"name"] != nil && [dict_user_info[#"name"] isKindOfClass:[NSNull class]] == NO) {
user_post.username = dict_user_info[#"name"];
if (user_post.username != nil) {
ser_post.username = user_post.username;
} else {
user_post.username = #"Username";
}
}
These are a couple of methods I wrote for my projects, try them :
/*!
* #brief Makes sure the object is not NSNull or NSCFNumber, if YES, converts them to NSString
* #discussion Sometimes JSON responses can contain NSNull objects, which does not play well with Obj-C. So when you access a value from a JSON and expect it to be an NSString, pass it through this method just to make sure thats the case.
* #param str The object that is supposed to be a string
* #return The object cleaned of unacceptable values
*/
+ (NSString *)cleanedJsonString:(id)str
{
NSString *formattedstr;
formattedstr = (str == [NSNull null]) ? #"" : str;
if ([str isKindOfClass:[NSNumber class]]) {
NSNumber *num = (NSNumber*) str;
formattedstr = [NSString stringWithFormat:#"%#",num];
}
return formattedstr;
}
/*!
* #brief Makes Sure the object is not NSNull
* #param obj Sometimes JSON responses can contain NSNull objects, which does not play well with Obj-C. So when you access a value from a JSON ( NSArray, NSDictionary or NSString), pass it through this method just to make sure thats the case.
* #return The object cleaned of unacceptable values
*/
+ (id)cleanedObject:(id)obj
{
return (obj == [NSNull null]) ? nil : obj;
}
/*!
* #brief A JSON cleaning function for NSArray Objects.
* #discussion Sometimes JSON responses can contain NSNull objects, which does not play well with Obj-C. So when you access a value from a JSON and expect it to be an NSArray, pass it through this method just to make sure thats the case. This method first checks if the object itself is NSNull. If not, then it traverses the array objects and cleans them too.
* #param arr The Objects thats supposed to be an NSArray
* #return The NSNull Cleaned object
*/
+ (NSArray *)cleanedJsonArray:(id)arr
{
if (arr == [NSNull null]) {
return [[NSArray alloc] init];
}
else
{
NSMutableArray *arrM = [(NSArray*)arr mutableCopy];
int i=0;
for (id __strong orb in arrM)
{
if (orb == [NSNull null])
{
[arrM removeObjectAtIndex:i];;
}
i++;
}
return arrM;
}
}
Just pass a JSON string, array or object to the appropriate method and the method will clean it for you.
Do yourself a favour and write a method that handles this and put it into an extension. Like
- (NSString*)jsonStringForKey:(NSString*)key
{
id result = self [key];
if (result == nil || result == [NSNull null]) return nil;
if ([result isKindOfClass:[NSString class]]) return result;
NSLog (#"Key %#: Expected string, got %#", key, result);
return nil;
}
You might even add some code that accepts NSNumber* results and turns them into strings, if that is what your server returns (some poster here had the problem that his server returned dress sizes as numbers like 40 or strings like "40-42" which makes something like this useful).
And then your code becomes one readable line
user_post.username = [dict_user_info jsonStringForKey:#"name"] ?: #"username";
I actually use several slightly different methods depending on whether I expect null, expect no value, expect an empty string or not, which gives me warnings when my assumptions are wrong (but always returns something that doesn't break).
try this:
if(!(user_post.username == (NSString *)[NSNull null]) )

Check if contain Null

When I print the following I get (null)
NSLog(#"%#", [[responseObject objectAtIndex:i] objectForKey:#"child"]);
Now I want to do a validation to check if it returns (null). How am I supposed to do this?
I tried the following but it doesn't work:
1.
if (![[[responseObject objectAtIndex:i] objectForKey:#"child"] isEqualToString:#"(null)"]) {
}
2.
if (![[[responseObject objectAtIndex:i] objectForKey:#"child"] isEqual:#"(null)"]) {
}
"null" isn't just a NSString. You should do some research into the concept of a null object.
What you're looking for can be written like this:
if (![[responseObject objectAtIndex:i] objectForKey:#"child"]) {
//key "child" not in dictionary
}
(null) is the representation of nil displayed by NSLog.
You can write the following:
if ([[responseObject objectAtIndex:i] objectForKey:#"child"] == nil) {
}
Or a shorter alternative:
if (![[responseObject objectAtIndex:i] objectForKey:#"child"]) {
}
Another way to check is to use string length. I know other answers are just as good, I am just giving OP and anyone else in future some more options.
NSString *childStr = [[responseObject objectAtIndex:i]objectForKey:#"child"];
if ([childStr length] < 1)
{
//no value specified - childStr is NULL
}
else
{
//there is something in the childStr - throw a party!
}
NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:#"hello"]) {
NSLog(#"only if not null show %#",[defaults objectForKey:#"hello"]);
}
This is a way to check it from User Defaults. It will only print if the saved object does not equal null.

iOS 8: handling data returned from iTunes Search API

I am using iTunes Search APIs to return the number of users that have reviewed my current app version. Since I haven't released the app yet, I have to handle the case where the iT search API returns nothing.
Here's the pertinent code:
NSDictionary *iTunesDict = [NSJSONSerialization
JSONObjectWithData:iTunesData options:0 error:&error];
NSArray *resultCount = #[[iTunesDict valueForKey:#"resultCount"]];
NSLog(#"%#", [resultCount objectAtIndex:0]);
if ([resultCount objectAtIndex:0] == 0) {
self.numberOfReviewers = #"0";
} else {
NSArray *reviewers = #[[[iTunesDict valueForKey:#"results"] valueForKey:#"userRatingCountForCurrentVersion"]];
if ([reviewers objectAtIndex:0] == nil) {
self.numberOfReviewers = #"0";
} else {
NSString *howManyReviewed = [[[reviewers objectAtIndex:0] objectAtIndex:0] stringValue];
self.numberOfReviewers = howManyReviewed;
}
My problem centers around the first if statement. Upon inspection, the value of...
[resultCount objectAtIndex:0] is: (__NSCFNumber *)(long)0
does not satisfy the condition in my first if.
What do I need to make a **(__NSCFNumber *)(long)0 **== 0??
It's returning the data as an NSNumber object. Use the compare: comparison function:
if ([resultCount[0] compare:#0] == NSOrderedSame) {
...
}
else {
...
}
What this is doing is comparing the resultCount object to an NSNumber with the value of 0 (you can use the literal #0 to short-hand an NSNumber as I've done above). compare: returns one of three values:
NSOrderedDescending
NSOrderedSame
NSOrderedAscending
This reads from left to right. So if I was to use NSOrderedDescending, this would read logically "is 0 smaller than resultCount" (in descending order from left to right).
For further reading, check out the comparing NSNumber objects documentation.
Alternatively, because you know it's a long, you can use the longValue method on NSNumber:
if ([resultCount longValue] == 0) {
....
}

Correct NSString output

I have talbeView that populate data from JSON. One my text label fill itself with NSString, and sometimes it output 0(NSNULL), which obviously, not suppose to be output on cell text label.
Following code:
if ([(cell.myNameLabel.text) isEqual: #"0(NSNull)"]){
cell.myNameLabel.text = #"No Name";
}
Isn't work, i wonder why?
How to fix that?
Data populated from JSON use here like this :
//use accordingly that it may contain either NSDictionary or NSArray.
NString *strValue = youJSONDataArray[indexPath.row];
if ([value isEqual:[NSNull null]] || value.length == 0) {
strValue == #"";
}
Set string value in UILabel like this:
cell.myNameLabel.text = strValue;
NSJSONSerialization uses NSNull to indicate a null JSON value.
Try this instead:
if ([cell.myNameLabel.text isEqual:[NSNull null]]) {
// …
}
But you'll probably want to strip out the NSNulls during parsing so that your code isn't littered with NSNull checks.
If a JSON response has a null value then its indicated by NSNull by NSJSONSerialization class so you can modify your code to
if ([cell.myNameLabel.text isEqual:[NSNull null]]) {
// your logic here
}

NSJSONSerialization returns "<null>" string

I'm try to set an NSDictionary to a JSON object retrieved from the server, I'm doing that in this line:
_peopleArray = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
It works fine and properly creates the dictionary. However, I have a problem, values that are null in the JSON object are stored as "<null>" string values in the dictionary. Is there any way to fix this or work around it? I want to avoid traversing through the entire thing and setting them to #"".
Thanks for any help!
~Carpetfizz
You are wrong. null values in JSON are not stored as <null> string values. They are stored as NSNull objects, which NSLog logs as <null>.
You can never trust what data you were given. If you assume you got an NSString and the server sends you a number, your code is likely to crash.
NSString* myJSONString = ...;
if ([myJSONString isKindOfClass:[NSString class]]) {
it is a string
} else {
it is not a string
}
There is nothing I guess, though it can be easily corrected from api makers, if not possible, you can always put a simple macro, I use to avoid such thing, follow macro below
#define Is_Empty(value) (value == (id)[NSNull null] || value == nil || ([value isKindOfClass:[NSString class]] && ([value isEqualToString:#""] || [value isEqualToString:#"<null>"]))) ? YES : NO
#define IfNULL(original, replacement) IsNULL(original) ? replacement : original
#define IsNULL(original) original == (id)[NSNull null]
#define SafeString(value) IfNULL(value, #"")
Usage
self.label.text=SafeString([dic objectForKey:#"name"]);

Resources