I have some JSON that comes back like this:
"items":[
{
"has_instore_image": false
}
]
If I output the value like this:
NSLog(#"has_instore_image val: %#", [item objectForKey:#"has_instore_image"]);
I get
has_instore_image val: 0
but if I test like this:
if([item objectForKey:#"has_instore_image"]==0){
NSLog(#"no, there is not an instore image");
}else{
...
It always goes to the else statement... hmmm.. How would you suggest I get the BOOL value and test? I've read through the BOOL questions here and am just confused this is not working as I'd anticipate.
thx
NSDictionary's instance method objectForKey returns an id, not a primitive value.
If it's a boolean, int, float, etc number-like value in JSON, it will serialized to an NSNumber by Apple's NSJSONSerialization class and most/all other common JSON parsers in iOS.
If you want to get the BOOL value out of it, you can do something like this:
BOOL has_instore_image = [[item objectForKey:#"has_instore_image"] boolValue];
You are comparing a pointer with an integer here
[item objectForKey:#"has_instore_image"]==0
You should use
[item objectForKey:#"has_instore_image"].integerValue==0
Also note that a BOOL of NO equals 0.
The NSLogstatement in your code prints a 0, but only because if you give NSLogan object as parameter, the objects descriptionis called.
i will suggest to hold these id type (returned from dictionary) to NSNumber .
NSNumber *boolNum=(NSNumber*)[item objectForKey:#"has_instore_image"];
after that you can get bool value from boolNum
[boolNum boolValue]
try this
if([boolNum boolValue]==NO){
NSLog(#"no, there is not an instore image");
}else
{
}
Related
I am creating an NSMutableDictionary and assigning an NSString (test and test1) to a parameter key.
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
if (test.length) {
dictionary[#"test"] = test;
}
if (test1.length) {
dictionary[#"test1"] = test1;
}
This method does work. However, I am going to eventually have more strings and don't want a bunch of if statements. I don't want the dictionary keys to exist if the string is empty or nil.
Not sure if there is a way around this.
I thought about creating a separate function that accepts an array of key string and array of string values and use a for loop to see if string value is empty. Then, return a dictionary once the for loop ends. However, you can't insert nil into an NSArray
Something like this
- (void)updateDic:(NSMutableDictionary *)dic withString:(NSString *)str {
if (!str || [str isEqualToString:#""]) {
return;
}
dic[str] = str;
}
And then just iterate over all strings and use that method.
What I'd do is create a NSMutableDictionary category, something like this:
NSMutableDictionary+CustomMethods.m:
- (void)setStringIfNotNil:(NSString *)string forKey:(id <NSCopying>)key {
if (!string || !string.length) { return; }
self[key] = string;
}
Then you can use it like this:
NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init];
[dictionary setStringIfNotNil:test forKey:#"test"]
[dictionary setStringIfNotNil:test1 forKey:#"test1"]
There are three ways according to me..
The first one use the category in which you have to write if condition only single time and you can use it in any class of your project.
Second one by making a separate method to do that task(to check string nil or not and adding into the dictionary).
And the third one , just add all in an array and and perform the action in a loop.
The syntax:
dictionary[#"test"] = test
will remove the value from the dictionary if test is nil (it's a difference between the normal -setObject:forKey: method and the -setObject:forKeyedSubcript: which that syntax invokes). However, that will not work for empty strings.
As mentioned in another answer, you could make an NSDictionary category method to check, then call that method instead.
You could also just use the regular dictionary[key] = value syntax, then when you are done, do:
[dictionary removeObjectsForKeys:[dictionary allKeysForObject:#""]];
If it's possible to have the keys repeated, and you don't want an empty string overriding an earlier valid valid, you would have to check each time -- either by the category method, or using a local macro or inline function or local method.
static inline void SetValidVal(NSMutableDictionary *dictionary, NSString *key, NSString *val) {
if (val.length) { dictionary[key] = val; }
}
or
#define MY_SET_VALID_VAL(dictionary, key, val) if ((val).length) dictionary[key] = (val)
If the key names need to be the same as the name of the local variable, you can play other games with macros (this also assumes the local variable name "dictionary":
#define MY_UPDATE_VAL(val) if (val.length) dictionary[##val] = (val)
Then MY_UPDATE_VAL(test1); would expand to:
if (test1.length) dictionary[#"test1"] = test1;
That's a bit magic though and probably not recommended.
Let's say I loaded a JSON string into an NSDictionary that had some numbers written as strings. The resulting NSDictionary might look something like this:
NSDictionary* example = #{
#"aNumber": #"1",
#"aFloat": #"2.9708",
#"aBool": #"true",
#"aNestedDict": #{
#"more": #"220",
#"evenMore": #"false",
#"anArray": #[
#"1",
#"2"
]
}
};
I want to parse the float, integer, and bool ('true', 'false', 'yes', 'no' - case insensitive) values into their respective Objective-c class types. I've looked around, but can't find any examples of built in APIs to do this.
(Enlarged since people aren't reading the question)
Am I stuck writing a recursive parser and converting each value manually, or does Apple offer a built-in API to recursively parse it for me?
There isn't an API to do it, however you can make a helper function to figure it out. The API that apple does provide however are helper functions on NSString, i.e.: .integerValue, .doubleValue, .boolValue. However not only is this limited to NSString, it's also not comprehensive / intelligent.
So if you want to parse the string into a variable of type BOOL you can do something as simple as:
- (NSNumber *)parseBool:(NSString *)value
{
if( [value caseInsensitiveCompare:#"yes"] == NSOrderedSame || [value caseInsensitiveCompare:#"true"] == NSOrderedSame )
{
return #YES;
} else if ([value caseInsensitiveCompare:#"no"] == NSOrderedSame || [value caseInsensitiveCompare:#"false"] == NSOrderedSame )
{
return #NO;
} else
{
return nil;
}
}
EDIT:
For int and double just use:
NSString *string = #"1";
NSInteger intValue = string.integerValue;
double doubleValue = string.doubleValue;
JSON supports strings, numbers with and without decimals, boolean values, null values, dictionaries and arrays. So anyone wanting to represent numbers and boolean values in JSON can just do that.
Anyone producing JSON should document what they are producing. So if they insist on representing a boolean value as a string, then they should document which possible strings will be used to represent true and false. And then it's just a matter of string comparison.
For numbers stored as string, you can use integerValue or doubleValue which works just fine for strings.
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.
for (NSDictionary *fbDictionary in self.latestReactionsArray) {
LatestReaction *latestReaction = [[LatestReaction alloc]init];
NSDictionary *subFBDictionary = [fbDictionary objectForKey:#"participant"];
NSString *facebookUserID = [subFBDictionary valueForKey:#"facebook_id"];
NSNumber* reactionIDNum = [fbDictionary valueForKey:#"reaction_id"];
int reactionID = [reactionIDNum intValue];
NSLog(#"what is name%# and %# and %d",facebookUserID, self.latestReactionsArray,reactionID);
}
I want to save all [fbDictionary valueForKey:#"reaction_id"] in an array or dictionary. How do I do this? Thanks.
Try this:
NSArray *reactionIDs = [self.latestReactionsArray valueForKey:#"reaction_id"];
That will give you an array of reaction IDs.
The reflection in Objective C is not powerful enough to get a usable list of properties that you want to map. Instead, you should implement a class method that returns a list of properties you want to map to JSON and use that.
Lastly, a common "Gotcha" is trying to add nil to a dictionary. You'll need to do a conversion from nil to [NSNull null] and back for the conversion to work properly.
I need to check if a certain array contains a certain object, and if it does, delete that object. If it hasn't got that object, the funciton is suposed to add it into the array. The problem is that the object is always added because the checking statement always return false.
Here's my current function:
- (void) myFunction:(NSString *)parameter {
if (![myMutableArray containsObject:parameter]) {
[myMutableArray addObject:parameter];
NSLog(#"%# added", parameter);
} else {
[myMutableArray removeObject:parameter];
NSLog(#"%# deleted", parameter);
}
}
containsObject is calling isEqual on each of the object in the arrays. What type of object are you checking for? If it's a custom object, override and implement the method isEqual.
I'm guessing you're trying to check the value of the object, but containsObject is actually calling isEqual which is comparing the reference to the object, and not its actual value.
if (![arrList containsObject:arrObj]) {
// do something
}
containsObject:
First you need to check which type data or object you are adding in this myMutableArray. According to your method you are checking in mutable array for string type that you have passed argument parameter. It may be possible that you are containing int or float array.
There may be issue of type casting in your array.If your is STRING type of data then you can use another method like this.
- (void) myFunction:(NSString *)parameter {
for (int i = 0 ; i < [myMutableArray count ] ; i++) {
if (![[myMutableArray objectAtIndex:i] isEqualToString:parameter]) {
[myMutableArray addObject:parameter];
NSLog(#"%# added", parameter);
}
else{
[myMutableArray removeObject:parameter];
NSLog(#"%# deleted", parameter);
}
}
}
Hope this will help you. If your object is not type of NSString then you need to convert.
You should implement isEqual: in your custom class. By default two objects are only identical if they share the same reference.
Also make sure to initialize your mutable array before using it.
EDIT:
It seems that your array's variable name are most probably mistyped.
myMutableArray
myMutbaleArray
You probably forgot to initialize your NSMutableArray. If not initialized, you are sending addObject messages to a nil object, which has no effect, and the array never contains what you previously added...
Of course, if the array is nil, then the contains check will always return false. According to the Objective-C docs:
If the method returns an object, any pointer type, any integer scalar
of size less than or equal to sizeof(void*), a float, a double, a long
double, or a long long, then a message sent to nil returns 0.
And 0 is false