I have the following response that returns from a block:
response: {
error = "";
success = 1;
}
I attempt to evaluate "success" but it never evaluates as equal to 1 only as "else":
NSLog(#"response: %#", responseObject);
NSInteger success = (NSInteger)responseObject[#"success"];
NSString *errorMessage = (NSString *)responseObject[#"error"];
if (success == 0) {
NSLog(#"success is false");
NSLog(#"JSON: %#", errorMessage);
saveCallback(NO, [self createErrorFromDescription:errorMessage]);
}else if (success == 1){
NSLog(#"success is true");
saveCallback(YES, nil);
}else{
NSLog(#"success is else");
NSLog(#"JSON: %#", errorMessage);
saveCallback(NO, [self createErrorFromDescription:errorMessage]);
}
What am I doing wrong?
NSInteger is a primitive and id is an object (actually a pointer to an object), in this case likely an NSNumber.
Directly casting the pointer to an object, to NSInteger will not transform it into a integer value type, it will just reinterpret the pointers memory as an integer.
To transform the number object to a integer value you would call integerValue on it.
(It could also be that the number is missing from the response or it could be returned as the NSNull object, hence the error checking below)
NSNumber *successNumber = responseObject[#"success"];
NSInteger success;
if (!successNumber || successNumber == [NSNull null]) {
// the response doesn't contain anything for the "success" key :(
}
// if successNumber is nil, this will be 0.
// if successNumber is the NSNull object, this will crash (unrecognized selector)
// Just be aware of both of those.
success = [successNumber integerValue];
NSInteger success = [responseObject[#"success"] integerValue];
Given that it appears you're using raw json, you need to be very careful that you don't use a NULL value; this will result in an exception.
Since there are many types of Null in Objective C, it's best to use class introspection to make sure your objects are valid.
NSDictionary *responseArray = responseObject;
NSInteger success=0;
if([responseObject isKindOfClass:[NSDictionary class]])
{
// responseObject is safe to subscript
NSNumber *successNumber = responseObject[#"success"];
// Use introspection; messaging nil doesn't cause an exception and returns nil
if ([successNumber isKindOfClass:[NSNumber class]])
{
// NSInteger is a primitive
success = [successNumber integerValue];
}
}
// If success is anything but zero, assume it's true
if (success)
{
NSLog(#"success is true");
}
else
{
NSLog(#"success is false");
}
Presumably, your success key is either 1 or 0, so you could simplify this code a bit. In general, though, this is how you'll want to deal with objects that may be NULL rather than simply nil.
Related
I'm using the following code to check if a NSNumber has nil value. So I'm converting the NSNumber to string and Im checking if its length is 0. If it is of zero, Im returning NSNull else Im returning the number itself.
- (id)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return [NSNull null];
}
return number;
}
Im invoking it as follows,
NSString *bodyString = [NSString stringWithFormat:#"[ \"%#\",{\"session_token\": \"%#\",\"request\": [\"GetAssigneeWiseCompliancesChart\",{\"country_id\": %#,\"business_group_id\": %#,\"legal_entity_id\": %#,\"division_id\": %#,\"unit_id\": %#,\"user_id\": %#}]}]",clientSessionId,clientSessionId,[self NSNullToNilForKey:countryId],[self NSNullToNilForKey:businessGroupId],[self NSNullToNilForKey:legalEntityId],[self NSNullToNilForKey:divId],[self NSNullToNilForKey:unitId], [self NSNullToNilForKey:userId]];
But the problem is that, though the if loop is getting invoked. The value returned from the if loop of NSNullToNilForKey is <null> instead of null. How can I sort this out?
You're creating a string from a format, all of the parameters are added by taking their description, what you're seeing is the description of the NSNull instance.
Your method should specifically return a string and you should choose explicitly what string you want to return.
- (id)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return #"NSNull";
}
return number;
}
try this
change the type anyobject id to NSNumber *
- (NSNumber *)NSNullToNilForKey:(NSNumber *)number
{
if ([[number stringValue] length] == 0){
return [NSNull null];
}
return number;
}
Sir I am using google place Autocomplete and I am finding coordinate of a place I am using below code but i found an error in returning statement-
there are 5 places name and placeID in finalarray
-(NSDictionary * ) checkArr
{
NSLog(#"%#",finalarray);
NSDictionary *dict = [finalarray objectAtIndex:0];
NSString *placeID = [dict objectForKey:#"place_ID"];
NSDictionary * dict1 = [self getquardinate:placeID];
return dict1;
}
I am finding above error in return statement while returning dictionary
- (NSDictionary * )getquardinate:(NSString*)placeID{
[_placesClient lookUpPlaceID:placeID callback:^(GMSPlace *place, NSError *error) {
if (error != nil) {
NSLog(#"Place Details error %#", [error localizedDescription]);
return ;
}
if (place != nil) {
NSNumber *lat = [NSNumber numberWithDouble:place.coordinate.latitude];
NSNumber *lon = [NSNumber numberWithDouble:place.coordinate.longitude];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:lat, #"latitude",lon, #"longitude", nil];
return dict; // above error in this line
}
}];
}
Your block has one plain return statement (returns void) and one statement return dict (returns an NSDictionary*). That's not allowed.
If you had defined the return type of the block as void, the second would give an error. If you had defined the return type of the block as NSDictionary*, the first would give an error. If you had defined the return type of the block as NSInteger, both would give an error.
You didn't specify the return type, leaving it to the compiler. After the first "return" the compiler thinks "well, return type must be void" so you get an error message on the second return.
PS. As trojanfoe remarked, you need to figure out how asynchronous calls work. What you are trying to do cannot possibly work that way. Another PS: What is a quardinate? Are you from Texas where "coordinate" sounds like "quardinate"?
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]) )
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) {
....
}
I have a JSON response from a web server that looks like this:
{"success":true, "token":"123456"}
and I want to use that in an if statement, and compare it with "YES".
However, doing this doesn't work:
NSDictionary *response = [response JSONValue]; // the JSON value from webservice response, converted to NSDictionary
if ([response objectForKey:#"success"]){} // does not work
if ([response objectForKey:#"success"] == YES){} // does not work
if ([[response objectForKey:#"success"] integerValue] == YES) {} // does not work...erroneous probably
How can I work around this? Typecasting in Boolean yields a warning too
since [response objectForKey:#"success"] does not work, what happens when you try [response valueForKey: #"success"]?
I suspect it returns a NSNumber and then you can do something like:
NSNumber * isSuccessNumber = (NSNumber *)[response objectForKey: #"success"];
if([isSuccessNumber boolValue] == YES)
{
// this is the YES case
} else {
// we end up here in the NO case **OR** if isSuccessNumber is nil
}
Also, what does NSLog( #"response dictionary is %#", response ); look like in your Console? I see the JSON library you're using does return NSNumber types for objectForKey, so I suspect you might not have a valid NSDictionary.
An alternative approach to this, which requires no conversion to NSNumber is something like below:
if ([response objectForKey:#"success"])
{
if ([[response objectForKey:#"success"] boolValue])
NSLog(#"value is true");
}