So I am parsing a twitter timeline. There is a field called "following" in the JSON response. It should be true or false.
But sometimes the field is missing.
When I do:
NSLog(#"%#", [[[timeline objectAtIndex:i] objectForKey:#"user"] objectForKey:#"following"]);
This is the output:
1
1
0
0
1
<null>
1
1
So how to check for those values?
NSArray and other collections can't take nil as a value, since nil is the "sentinel value" for when the collection ends. You can find if an object is null by using:
if (myObject == [NSNull null]) {
// do something because the object is null
}
If the field is missing, NSDictionary -objectForKey: will return a nil pointer. You can test for a nil pointer like this:
NSNumber *following = [[[timeline objectAtIndex:i] objectForKey:#"user"] objectForKey:#"following"];
if (following)
{
NSLog(#"%#", following);
}
else
{
// handle no following field
NSLog(#"No following field");
}
It's not the timeline element that's null. It's either the "user" dictionary or the "following" object that's null. I recommend creating a user model class to encapsulate some of the json/dictionary messiness. In fact, I bet you could find an open source Twitter API for iOS.
Either way, your code would be more readable as something like:
TwitterResponse *response = [[TwitterResponse alloc] initWithDictionary:[timeline objectAtIndex:i]];
NSLog(#"%#", response.user.following);
TwitterResponse above would implement a readonly property TwitterUser *user which would in turn implement NSNumber *following. Using NSNumber because it would allow null values (empty strings in the JSON response).
Hope this helps get you on the right track. Good luck!
for checking array contain null value use this code.
if ([array objectAtIndex:0] == [NSNull null])
{
//do something
}
else
{
}
Related
I want to get data from JSON service. Only iOS 7 version crash when get data from JSON value.
It returns from JSON service below that:
{
voteAverageRating = 0;
voteCount = 0;
}
My code
int voteCount = [listDic objectForKey:#"voteCount"] intValue] ;
_LB_voteNumber.text = [NSString stringWithFormat:#"(%i)",voteCount];
Its work for iOS 5,5.1,6.0,6.1 but it crash only iOS7 version. It gave this error:
0x00098117 _mh_execute_header [NSNull intValue]: unrecognized selector
sent to instance
Then i changed my code below that;
NSString *voteCount = [listDic objectForKey:#"voteCount"] ;
_LB_voteNumber.text = [NSString stringWithFormat:#"(%#)",voteCount];
When runs this code. It crashed again only iOS 7 version. It gave this error:
0x00098117 _mh_execute_header [NSNull length]: unrecognized selector
sent to instance
How can i solve this problem ?
Put a check before accessing the value from JSON like,
if([NSNull null] != [listDic objectForKey:#"voteCount"]) {
NSString *voteCount = [listDic objectForKey:#"voteCount"];
/// ....
}
Reason for checking is, collection objects like NSDictionary do not allow values to be nil, hence they are stored as null. Passing intValue to a NSNull will not work as it will not recognise this selector.
Hope that helps!
As the others have said, JSON null will be deserialized to NSNull. Unlike nil, You cannot send (most) messages to NSNull.
One solution is to add an implementation of -intValue on NSNull via category:
#implementation NSNull (IntValue)
-(int)intValue { return 0 ; }
#end
Now your code will work since sending -intValue to NSNull will now return 0
Another option: You could also add an "IfNullThenNil" category to NSObject...
#implementation NSObject (IfNullThenNil)
-(id)ifNullThenNil { return self ; }
#end
#implementation NSNull (IfNullThenNil)
-(id)ifNullThenNil { return nil ; }
#end
Now, your code becomes:
int voteCount = [[[listDic objectForKey:#"voteCount"] ifNullThenNil] intValue] ;
Just add a call to -ifNullThenNil wherever you access values from a JSON object.
For me this is worked
NSArray* merStore = [tmpDictn objectForKey:#"merchantStore"];
if ([merStore isKindOfClass:[NSArray class]] && merStore.count !=0)
{
for(int n = 0; n < merStore.count; n++)
{
NSMutableDictionary *storeDic = [merStore objectAtIndex:n];
[latitudeArray addObject:[storeDic objectForKey:#"latitude"]];
}
}
I hope it helps some one. If you need any help let me know.
That's quite normal. JSON can send null values to your app. If it does, then this is done intentionally by the server and it expects you to handle it. Figure out what the correct behaviour is when a null value is received. Then when you get an object that could be a null value, check
if (object == [NSNull null])
{
// stuff to handle null objects
}
else
{
// stuff to handle non-null objects
}
The real problem isn't that your app crashes, but that your app doesn't handle JSON data that it is supposed to handle.
I have a code like that
if ([dataArray valueForKey:#"success"]) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
} else {
NSLog(#"no feed found ");
}
dataArray is a NSMutableArray which ultimately contains a JSON Dictionary.
but I am getting the same console output independent of success either TRUE or FALSE, but my console output is always same.my console output is:
for FALSE or NO:
self.feedsArray: (
{
action = register;
message = "Invalid parameters";
success = 0;
}
)
and for TRUE or YES:
self.feedsArray: (
{
action = register;
message = "valid parameters";
success = 1;
}
)
in both cases if part is executed.
in NSUserDefaults there is a method boolForKey but how to do this in case of NSMutableArray.
You need to read the fine print for [NSArray valueForKey:], specifically:
Returns an array containing the results of invoking valueForKey: using
key on each of the array's objects.
and:
The returned array contains NSNull elements for each object that
returns nil.
So if the array contains, say, 3 objects and none of them have a success key then you will get an array of 3 NSNull objects returned.
Therefore the if statement will fire whenever dataArray is non-empty, which is obviously not what you intended.
You should check the contents of the returned array:
BOOL succeeded = NO;
NSArray *results = [dataArray valueForKey:#"success"];
for (NSObject *obj in results) {
succeeded = [obj isKindOfClass:[NSNumber class]] && [(NSNumber *)obj boolValue];
if (succeeded)
break;
}
if (succeeded) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
} else {
NSLog(#"no feed found ");
}
You can do this in simple way:
What i see in your response json value is, you have dictionary in dataArray at index 0
NSMutableDictionary *responseDict = [dataArray objectAtIndex:0];
if([[responseDict objectForKey:#"success"] boolValue])
{
NSLog(#"Success: 1");
}
{
NSLog(#"Success: 0");
}
Use index instead of key for an array.
NSDictionary dictionary = (NSDictionary *)dataArray[0];
if ([(NSNumber *)[dictionary objectForKey:#"success"] boolValue]) {
// ...
}
otherwise use if([[[dataArray objectAtIndex:0] valueForKey:#"success"] isEqualToString:#"1"])
An array does not store keys, the only way to access items in an array is by index.
You should be using an NSDictionary/NSMutableDictionary instead. If you want to use a bool store it as a NSNumber, [NSNumber numberWithBool:YES] and then use the instance method valueForBool to read it back.
Try this
if ([[dataArray valueForKey:#"success"]isEqualToString:#"1"]) {
[self.feedsArray addObjectsFromArray:dataArray];
NSLog(#"self.feedsArray: %#",self.feedsArray);
}
else {
NSLog(#"no feed found ");
}
It 'll work out.
use this if you want bool value
if([[dataArray valueForKey:#"success"] boolValue])
{
//i.e success is true
}
if response contains array of dictionaries then we can use loop and check condition,
here i is index variable of array,
if([[[dataArray objectAtIndex:i] objectForKey:#"success"] boolValue])
{
// success is true ,
}
Replace you code line
if ([dataArray valueForKey:#"success"]) {
}
with
if ([[dataArray valueForKey:#"success"] integerValue]) {
}
Hope it will work for you.
its working with replacing the line with
if ([[[dataArray objectAtIndex:0] valueForKey:#"success"] boolValue])
I did search on how to check if NSDictionary key exists or not and came up with the solution. But still it throws me an error saying adding null value to the key.
I am not sure if my code is correct or not. If anyone has any idea about this can help me.
NSDictionary *result;
id myImageURL = [result objectForKey:#"url"];
if ((NSNull *)myImageURL == [NSNull null])
myImageURL = #"";
id myImage = [result objectForKey:#"image"];
if ((NSNull *)myImage == [NSNull null])
myImage = #"";
Check if null add nothing and if not add the value. But it still gives me an error dont know why.
/****OUTPUT*****/
2011-08-11 14:56:06.668 Tab_Table_Win[6510:207] RESULTS : {
image = "<UIImage: 0xbc332c0>";
url = "http://a3.twimg.com/profile_images/999228511/normal.jpg";
}
2011-08-11 14:56:06.669 Tab_Table_Win[6510:207] url : http://a3.twimg.com/profile_images/999228511/normal.jpg
2011-08-11 14:56:06.670 Tab_Table_Win[6510:207] IMage : <UIImage: 0xbc332c0>
/*****Breaks Here ***/
2011-08-11 14:56:06.876 Tab_Table_Win[6510:207] RESULTS : {
}
2011-08-11 14:56:06.878 Tab_Table_Win[6510:207] url : (null)
2011-08-11 14:56:06.879 Tab_Table_Win[6510:207] IMage : (null)
2011-08-11 14:56:06.881 Tab_Table_Win[6510:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil key'
Correct answer is :
NSDictionary *result;
NSURL *myImageURL = [result objectForKey:#"url"];
UIImage *myImage = [result objectForKey:#"image"];
/**** Correct way ****/
if (myImageURL != nil && myImage != nil) {
[images setObject:myImage forKey:myImageURL];
}
Thank you for all the explanation.
Tommy explained this perfectly.
What I recommend is create an extension of the NSDictionary class like:
#import <Foundation/Foundation.h>
#interface NSDictionary (Safety)
- (id)safeObjectForKey:(id)aKey;
#end
And the implementation file:
#import "NSDictionary+Safety.h"
#implementation NSDictionary (Safety)
- (id)safeObjectForKey:(id)aKey {
NSObject *object = self[aKey];
if (object == [NSNull null]) {
return nil;
}
return object;
}
#end
And instead of using [dictionary objectForKey:#"keyName"]; in your code, use
[dictionary safeObjectForKey:#"keyName"];
This way, as Tommy explained, you'd be sending a method call to a nil which wouldn't crash the app but your object would get a nil value.
Hope this helps.
Whenever I try to check if an object being returned from a dictionary is null, I do this:
id obj = [myDictionary objectForKey:entityKeyName];
if (obj == [NSNull null]) {
// do something
}
Then in your code, it would be:
NSDictionary *result;
NSString *myImageURL = [result objectForKey:#"url"];
if (myImageURL == [NSNull null])
myImageURL = #"";
That's what I would do in your code.
Also, just making sure, is the NSDictionary result defined? In your code, it doesn't have anything it's being set to. It's just being defined as variable you plan on using called results
the answer below worked for me:
https://stackoverflow.com/a/2784675/936957
if ([dictionary objectForKey:key]) {
// previously stored data for "key"
}
Also note that you can get array of the keys in a dictionary using
[dictionary allKeys]
If an object doesn't exist for a key, NSDictionary will return nil. An NSNull is an actual object, and therefore a distinct thing. It's like the distinction between being able to record that there was a value and the value as null, and not recording whether there was a value. It also rests a bit on you thinking in C terms of the indirection of a pointer to an object rather than just an object, so it's not completely semantically pleasing from that perspective.
In Objective-C, you may send any message to nil and the result is guaranteed to be nil (or 0). So if your code is designed to ensure that you have a safe object reference, as you might in C++, then what you're doing is unnecessary. Compound statements like:
object = [[Type alloc] init];
Are always explicitly safe, even if alloc fails and returns nil. All that'll happen is that the call to init won't do anything at all, and object will end up with the value nil because the result of sending of init to nil is also nil.
That being said, the answers provided by Bill and Emmanuel should be correct. Compare your result either directly to nil or implicitly to zero. If you're getting a crash later on, I'll guess it's because you're expecting myImageUrl and myImage to be types other than NSString (I notice you've used the typeless id in your original code) and sending them a message they don't respond to.
NSDictionary *result;
NSString *myImageURL = [result objectForKey:#"url"];
if (myImageURL == NULL)
myImageURL = #"";
NSString *myImage = [result objectForKey:#"image"];
if (myImageURL == NULL)
myImage = #"";
See if that works, rather than overthinking the NULL class.
this another option:
if (![result objectForKey:#"image"])
{
NSLog(#"doesn't exist");
}
if ([result objectForKey:#"image"])
{
NSLog(#"exist");
}
that was not work for me, i figured it out like this
id myImageURL = [result objectForKey:#"url"];
if ([myImageURL isKindOfClass:[NSNull class]])
myImageURL = #"";
Alright here's the actual answer which #Iomec almost had
UIImage *myImage = ([result objectForKey:#"image"] != [NSNull null] ? [result objectForKey:#"image"] : nil);
That is the actual correct answer because, it comes as null and when you say myImage = [receivedObject...]; then if myImage = nil, you are in effect casting a null value(nil) into a class which is an exception, if not a running bug.
You should:
1) test for NSNull null value
2) if not nil then assign
If you code hasn't bugged out yet, it will in production when you have 8 apps running in the background one day.
I got the same issue with JSONKit. The implementation there is
- (id)objectForKey:(id)aKey
{
[...]
return((entryForKey != NULL) ? entryForKey->object : NULL);
}
So this will definitely return NULL if the object isn't there. I check it like the following
NSArray* array = [myDictionary objectForKey:#"a"];
if((NSNull*)arrays!=[NSNull null])
{
[...]
}
1. Results Dictionary after JSON parsing:
//if hits success
{"result":{"action":"authentication","statusCode":"200","statusMsg":"No
error, operation
successful.","count":1,"data":{"apiToken":"509e6d21-4f69-4ded-9f3d-4537e59e6a3a","userId":8,"role":"Bidder","firstName":"bidder","lastName":"bidder","emailAddress":"1cbrecbill#wricapitalgroup.com","countiesCovered":"21,16,11,1,2,14,32,3,4,25,13,15,5,41,43,6,12,7,24,39,17,36,42,44,29,40,8,18,19,27,9,28,23,10,33,26,35,20,30,22,34,31"}}}
//Data is Dictionary inside Result
-----------------------------------------------------------------------
I had an error showing : NULL DATACould not cast value of type 'NSNull' (0xda7058) to 'NSDictionary' (0xda6d74) and the result was
the following.
({"result":{"action":"authentication","statusCode":"204","statusMsg":"Invalid
Username or Password","count":null,"data":null}})
I fixed the Null check of dictionary.
if (result.objectForKey("data") is NSNull)
{
print ("NULL DATA")
}
else
{
let data = result["data"]as! NSDictionary
print (data)
}
Might want to add a bit more safety by checking to make sure it is NOT a string instead of just checking if it IS a nil. (To make sure it is not a number or anything else you might not want.)
id myImageURL = [result objectForKey:#"url"];
if (![myImageURL isKindOfClass:[NSString class]]) {
myImageURL = #"";
}
When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from this way to avoid from crash.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}
I've an NSString thats populated from some data returned via JSON.
The code works great under normal circumstances but there is an occasion when i get returned by the JSON.
When i do a check to see if my NSString == nil or == null it fails the test.
But the fact that the NSString contains crashes my app.
So does have some special meaning in Objective C? Or should i just do a string compare and see if the string is equal to rather than being nil and handle it that way.
This has me a little confused.
Many Thanks,
Code
<null> is what NSNull returns for its -description method. You need to also check for
myString == [NSNull null]
in this case.
Additional info: IIRC the common Objective-C JSON stuff will use [NSNull null] for nulls in the JSON structure, to differentiate the value from one that simply isn't there.
NSString * is just a pointer to a NSString object.
To test for null pointer:
NSString *str;
if (str) {
// str points to an object
if ([str length] == 0) {
// string is empty
}
} else
// str points to nothing
}
If you want to check for whitespace, you can trim the NSString with stringByTrimmingCharactersInSet.
You could check to see if it's null by.
if ([str isKindOfClass:[NSNull class]]) {
// str is null.
}
I did it this way:
if([string isKindOfClass:[NSNull class]]) {
NSLog(#"This is JSON null");
} else {
NSLog(#"This is a string, do what you wanna do with it");
}
I am trying to implement this button action, but the if statement is not evaluating to be true. I have a situation where the value in that "School" dictionary will not always have a website stored. For that reason i want to check, but what do i check against. If "nil" is not stored there when there is not a value, then what is?
-(IBAction) btnVisitWebsite_clicked :(id)sender {
if([School objectForKey:WEBSITE_KEY] == nil){
UIAlertView *NoWebsite = [[UIAlertView alloc]initWithTitle: #"No Website"
message:#"The selected school has not listed a website"
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
NoWebsite.tag = 15;
[NoWebsite show];
[NoWebsite release];
NoWebsite = nil;
}
else{
NSMutableString *WebsiteVisit = [[NSMutableString alloc] initWithString: #"http://"];
[WebsiteVisit appendString:[School objectForKey:WEBSITE_KEY]];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: WebsiteVisit]];
[WebsiteVisit release];
}
}
If it is possible that the Website is an empty string you should use the following:
if(![School objectForKey:WEBSITE_KEY]
|| ([[School objectForKey:WEBSITE_KEY] isKindOfClass:[NSString class]] && [(NSString*)[School objectForKey:WEBSITE_KEY] length]==0)){
// no website
} else { /* has website*/ }
Have you tried to use NSLog to print the object for the key ?
NSLog(#"School[WEBSITE_KEY]=<%#>", [School objectForKey:WEBSITE_KEY]);
Maybe it is not nil ?
See if the requested school is in the NSDictionary by checking if it has an entry
BOOL containsKey = [[School allKeys] containsObject:WEBSITE_KEY];
If there is no school website, there should not be an directory entry for the WEBSITE_KEY.
An NSDictionary cannot contain nil. If the key exists it has to contain an object. The objectForKey: method will return nil if there is no object defined for a specific key. You can however store [NSNull null] as a null placeholder in a dictionary or array. So you can check for that, it all depends how your dictionary is populated.
[School objectForKey:WEBSITE_KEY] == nil || [School objectForKey:WEBSITE_KEY] == [NSNull null]
Also ensure you're not confusing #"" with a nil or no value. If it's not nil and not [NSNull null] then it's best to log it, and perhaps look at what object is being stored:
NSLog(#"Description: %#", [School objectForKey:WEBSITE_KEY]);
NSLog(#"Class: %#", [[School objectForKey:WEBSITE_KEY] class]);
If the class returns a NSString or NSCFString then it looks like it contains an empty string. Which you can check for. Here is the full blown statement:
id schoolWebsite = School objectForKey:WEBSITE_KEY];
if (schoolWebsite && schoolWebsite != [NSNull null] && [schoolWebsite isKindOfClass:[NSString class]] && [schoolWebsite length] > 0)) {
// There is definitely a non-empty string for that key!
} else {
// Not valid
}
This will be good to use as you may be unsure of exactly what is stored in the dictionary as others will be populating it. You can never be too careful!