null check for dictionary object before call to intvalue still leads to intvalue calls on null object - objective-c

I get an array of dictionaries back from reading json off a web server and use the following to make sure I got a particular key in the first dictionary in the array before getting its int value:
if([jsonObject[0] objectForKey:#"votes"]!= nil)
{
int votes = [[jsonObject[0] objectForKey:#"votes"] intValue];
[[UserObject userUnique] updateVotes:votes];
}
However, my app still occasionally crashes saying I have called intValue on Null. I have also tried structuring the control statement as
if([jsonObject[0] objectForKey:#"votes"])
but this also leads to the same error/app crashing. My syntax seems in line with accepted answers on SO (Check if key exists in NSDictionary is null or not). Any suggestions for what else/how else I should check the existence of key-value pair for applying intvalue?
Thank you for any advice.

There is a difference between nil and null. nil is not an object: it's a special pointer value. null (as retuned by [NSNull null]) is an object: it's needed because it can be stored in containers like NSDictionary.
NSString *votesString = [jsonObject[0] objectForKey:#"votes"];
if (votesString != nil && votesString != [NSNull null])
{
int votes = [votesString intValue];
[[UserObject userUnique] updateVotes:votes];
}
EDIT: An answer to #SunnysideProductions question
The post you mentioned recommends a way of turning null values into nil values by creating a -safeObjectForKey: method. You are not using -safeObjectForKey:, you are using the default -objectForKey: method.

Be consecutive in your code. Don't run with methods. It would be better add more null- and type-checks in particular in working with json. Let's do it:
if (jsonObject && [jsonObject isKindOfClass:[NSArray class]])
{
NSArray *jsonArray=(NSArray *)jsonObject;
if (jsonArray.count>0)
{
id firstObject=jsonArray[0];
if ([firstObject isKindOfClass:[NSDictionary class]])
{
NSDictionary *jsonDict=(NSDictionary *)firstObject;
id votesNumber=jsonDict[#"votes"];
if (votesNumber && [votesNumber isKindOfClass:[NSNumber class]])
{
int votes=[votesNumber intValue];
[[UserObject userUnique] updateVotes:votes];
}
}
}
}
Now the code is more safe. Does it still crash?

When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}

Related

How to check if JSON object contains values

I have a JSON array that I parse. I parse the values from the key Staff, however sometimes the Staff object contain no values;
Expected return;
But sometimes it returns:
Which causes the app to crash because key[#"staff"][#"staff_id"] doesnt exist.
Ive tried:
if (key[#"staff"][#"staff_id"]){
//Parse staff
}
else{
//staff is empty
}
But this crashes as well because I think it still looks for the [#"staff_id"] which doesnt exist.
I've also tried
if (![key[#"staff"][#"staff_id"] isKindOfClass:[NSNull class]])
And
if (![key[#"staff"] isKindOfClass:[NSNull class]])
Any help is greatly appreciated. :)
That's a great example of shitty backend.
On the first example staff is a Dictionary, on the second example is an Array.
You need to ask your backend developer, to decide and always return either Array, or Dictionary.
BTW, you can workaround it
if ([key[#"staff"] isKindOfClass:[NSDictionary class]] && key[#"staff"][#"staff_id"]) {
id staffId = key[#"staff"][#"staff_id"];
} else {
// Staff is empty
}
You will only get object of class NSNull if the JSON contained a null value. For example a dictionary { "key": null } will contain a key/value pair with a key "key" and a value [NSNull null]. Instead of using "isKindOfClass" you can compare with [NSNull null], because there is only ever one NSNull object. If your JSON doesn't contain null values, that won't happen.
If your JSON sometimes contains a dictionary, and sometimes an array, well that's tough. Blame the guys creating the JSON. You can write for example:
id keyObject = ...;
NSDictionary* keyDictionary = keyObject;
NSArray* keyArray = keyArray;
if ([keyDictionary isKindOfClass:[NSDictionary class]]) {
.. you've got a dictionary
} else if ([keyArray isKindOfClass [NSArray class]]) {
.. you've got an array
} else if (keyObject == nil) {
.. there wasn't actually any key object
} else if (keyObject == [NSNull null]) {
.. your JSON contained "key": null
} else {
.. your JSON contained a string, number, or boolean value
}

Is nil and (NSString *)[NSNull null] equivalent in checking empty NSString object

I have a NSString object,
NSString *aString;
then are the two following versions equivalent?
Version 1 :
if ( (NSString *)[NSNull null] == aString )
{
// Logic handling
}
Version 2 :
if ( nil == aString )
{
// Logic handling
}
Reference Posts
Difference among nil, Nil, and null
How to detect if NSString is null?
Apple's NSNull Class Reference
How do I test if a string is empty in Objective C?
Update - Test Result
My simple test result shows that the above two versions have different behaviors:
When aString is initialized and then assigned with nil:
false for expression in version 1,
true for expression in version 2.
When aString is initialized with the value of #"".
false for expression in version 1,
false for expression in version 2.
So it's clear that the two versions are not equivalent in their behavior.
The test code:
NSString *aString = nil;
NSString *bString = [NSString stringWithFormat:#""];
if ((NSString *)[NSNull null] == aString) {
NSLog(#"a1 - true");
} else {
NSLog(#"a1 - false");
}
if (nil == aString) {
NSLog(#"a2 - true");
} else {
NSLog(#"a2 - false");
}
if ((NSString *)[NSNull null] == bString) {
NSLog(#"b1 - true");
} else {
NSLog(#"b1 - false");
}
if (nil == bString) {
NSLog(#"b2 - true");
} else {
NSLog(#"b2 - false");
}
Console output:
2013-10-31 00:56:48.132 emptyproject[31104:70b] a1 - false
2013-10-31 00:56:48.133 emptyproject[31104:70b] a2 - true
2013-10-31 00:56:48.133 emptyproject[31104:70b] b1 - false
2013-10-31 00:56:48.133 emptyproject[31104:70b] b2 - false
Update - What Do I Mean "Empty string"**
Now I've made it clearer that it's different for a NSString object to be nil and for it to be a valid initialized instance holding an empty string value of #"". What I really need in this post is that how to test if my NSString object is successfully initialized, that is, if aString is nil. I want to know if there is any difference for the above two versions of test code.
[NSNull null] and nil are not equivalent. [NSNull null] is meant to represent the concept of NULL (as in no object) in cases where nil cannot be used, for example in an NSArray (as you can only insert objects in them). [NSNull null] is an object (always the same object), while nil is a pointer to 0.
NSHipster has a nice discussion here. He says:
NSNull is used throughout Foundation and other frameworks to skirt
around the limitations of collections like NSArray and NSDictionary
not being able to contain nil values. You can think of NSNull as
effectively boxing the NULL or nil value so that it can be used in
collections.
If you have:
NSString *aString;
if ( aString == (NSString *)[NSNull null] )
{
// Logic handling
}
then something's wrong, aString should point to an NSString object (or subclass), or nil. But not [NSNull null] which is an object of a different class, you shouldn't cast from one to the other.
EDIT:
Given in the comments you state that you wish to check if the string is empty (as in #""), that is different. See this question. An empty string is an NSString object, it is not nil and it is not [NSNull null].
they are not the same, the NSNull is a valid object (inherited from NSObject) opposite a nil pointer, which points to nothing.
that is how you can check, whether an object is an NSNull object, but you first version is also okay.
id _object = // any kind of NSObject ...
if ([_object isKindOfClass:[NSNull class]]) {
// Logic handling
}
nil means nothing.
[NSNull null] is an object, instance of class NSNull
== means equality
something equals to something else is not the same as something is equal to nothing
[NSNull null] returns the singleton instance of NSNull.
aString == [NSNull null] compares two pointers. As long as aString does not point to the NSNull singleton, they will never be equal.
If you want to match a string to nil:
1. if(aString.length==0)
{
}
2.if(sString isEqualToString:#"")
{
}
3.if(aString!=nil)
{
} else
{
//do your stuff here
}
+(NSString*)replaceNullValuesWithEmptyString:(id)tempObj
{
if (([tempObj isKindOfClass:[NSNull class]])||
(tempObj == nil) ||
(tempObj == (id)[NSNull null])||
[tempObj isEqual:[NSNull null]] ||
[tempObj isEqual:nil]) {
}
else {
if([tempObj respondsToSelector:#selector(isEqualToString:)]) {
if ([tempObj isEqualToString:#"<null>"] ||
[tempObj isEqualToString:#"(null)"]) {
}
else {
if ([tempObj respondsToSelector:#selector(length)]) {
if ([tempObj length]>0) {
NSLog(#"Check Passed.");
return tempObj;
}
}
}
}
}
NSLog(#"Check failed.");
return #"";
}

Objective C NSPredicate predicateWithBlock removing nil/null values

I am trying to populate an array by taking an existing array and removing nil values from it. The array was populated from a the JSON response of an http call. Sometimes the array has a null value at the end, and the easiest way to remove that value so I wouldn't have to handle it everywhere in my code would be to use NSArray's filteredArrayUsingPredicate: to assign the variable into the instance variable I use throughout my class.
NSArray *respAgencyList = (NSArray*) [JSON valueForKeyPath:#"xml.path.to.data" ];
NSLog(#"data before filter: %#", respAgencyList);
// prints: ( { domain: "foo.com", name:"foobar"}, "<null>" });
if (respAgencyList != nil && respAgencyList.count > 0) {
agencies = [respAgencyList filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
NSLog(#"Evaluated object is %#", evaluatedObject); //prints <null> for the null value
BOOL ret = evaluatedObject != nil;
return ret;
}]];
}
In the above code the return value is always YES. However, when I put the debugger on and step through it I see:
evaluatedObject = id 0x00000000
Isn't this a null/nil value? What is different about this value compared to nil?
You should also check for NSNull, which can be placed into an NSArray since it is a proper object.
BOOL ret = (evaluatedObject != nil && [evaluatedObject isKindOfClass:[NSNull class]] == NO);
It is impossible for an NSArray to contain a nil element.
Some enumeration methods do hand you nil after the enumeration, as a signal that you've reached the end, but the nil is not in the array — it's just a signal, and you are not expected to do anything serious with it. However, I do not know whether this is one of them.
I suggest that instead of trying to remove nil from the array, which is impossible since nil was never there in the first place, you examine the array directly (log it, look in the debugger, whatever) and assure yourself that what you're trying to do is unnecessary.

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 if an NSDictionary or NSMutableDictionary contains a key?

I need to check if an dict has a key or not. How?
objectForKey will return nil if a key doesn't exist.
if ([[dictionary allKeys] containsObject:key]) {
// contains key
}
or
if ([dictionary objectForKey:key]) {
// contains object
}
More recent versions of Objective-C and Clang have a modern syntax for this:
if (myDictionary[myKey]) {
}
You do not have to check for equality with nil, because only non-nil Objective-C objects can be stored in dictionaries(or arrays). And all Objective-C objects are truthy values. Even #NO, #0, and [NSNull null] evaluate as true.
Edit: Swift is now a thing.
For Swift you would try something like the following
if let value = myDictionary[myKey] {
}
This syntax will only execute the if block if myKey is in the dict and if it is then the value is stored in the value variable. Note that this works for even falsey values like 0.
if ([mydict objectForKey:#"mykey"]) {
// key exists.
}
else
{
// ...
}
When using JSON dictionaries:
#define isNull(value) value == nil || [value isKindOfClass:[NSNull class]]
if( isNull( dict[#"my_key"] ) )
{
// do stuff
}
I like Fernandes' answer even though you ask for the obj twice.
This should also do (more or less the same as Martin's A).
id obj;
if ((obj=[dict objectForKey:#"blah"])) {
// use obj
} else {
// Do something else like creating the obj and add the kv pair to the dict
}
Martin's and this answer both work on iPad2 iOS 5.0.1 9A405
One very nasty gotcha which just wasted a bit of my time debugging - you may find yourself prompted by auto-complete to try using doesContain which seems to work.
Except, doesContain uses an id comparison instead of the hash comparison used by objectForKey so if you have a dictionary with string keys it will return NO to a doesContain.
NSMutableDictionary* keysByName = [[NSMutableDictionary alloc] init];
keysByName[#"fred"] = #1;
NSString* test = #"fred";
if ([keysByName objectForKey:test] != nil)
NSLog(#"\nit works for key lookups"); // OK
else
NSLog(#"\nsod it");
if (keysByName[test] != nil)
NSLog(#"\nit works for key lookups using indexed syntax"); // OK
else
NSLog(#"\nsod it");
if ([keysByName doesContain:#"fred"])
NSLog(#"\n doesContain works literally");
else
NSLog(#"\nsod it"); // this one fails because of id comparison used by doesContain
Using Swift, it would be:
if myDic[KEY] != nil {
// key exists
}
Yes. This kind of errors are very common and lead to app crash. So I use to add NSDictionary in each project as below:
//.h file code :
#interface NSDictionary (AppDictionary)
- (id)objectForKeyNotNull : (id)key;
#end
//.m file code is as below
#import "NSDictionary+WKDictionary.h"
#implementation NSDictionary (WKDictionary)
- (id)objectForKeyNotNull:(id)key {
id object = [self objectForKey:key];
if (object == [NSNull null])
return nil;
return object;
}
#end
In code you can use as below:
NSStrting *testString = [dict objectForKeyNotNull:#"blah"];
For checking existence of key in NSDictionary:
if([dictionary objectForKey:#"Replace your key here"] != nil)
NSLog(#"Key Exists");
else
NSLog(#"Key not Exists");
Because nil cannot be stored in Foundation data structures NSNull is sometimes to represent a nil. Because NSNull is a singleton object you can check to see if NSNull is the value stored in dictionary by using direct pointer comparison:
if ((NSNull *)[user objectForKey:#"myKey"] == [NSNull null]) { }
Solution for swift 4.2
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I'd suggest you store the result of the lookup in a temp variable, test if the temp variable is nil and then use it. That way you don't look the same object up twice:
id obj = [dict objectForKey:#"blah"];
if (obj) {
// use obj
} else {
// Do something else
}
if ([MyDictionary objectForKey:MyKey]) {
// "Key Exist"
}
As Adirael suggested objectForKey to check key existance but When you call objectForKeyin nullable dictionary, app gets crashed so I fixed this from following way.
- (instancetype)initWithDictionary:(NSDictionary*)dictionary {
id object = dictionary;
if (dictionary && (object != [NSNull null])) {
self.name = [dictionary objectForKey:#"name"];
self.age = [dictionary objectForKey:#"age"];
}
return self;
}
if ( [dictionary[#"data"][#"action"] isKindOfClass:NSNull.class ] ){
//do something if doesn't exist
}
This is for nested dictionary structure