Objective-C - "success" not equal to "success" - objective-c

The basic gist: I've got some JSON coming back from a webservice to validate a login; that part works. I'm pulling values out of the array into an NSDictionary; that part works. I need to check one of the values that comes back to know if it was successful or not. That's where it's failing. And as far as I can tell, it's telling me that "success" is not equal to "success".
NSDictionary *jsonArray = [NSJSONSerialization JSONObjectWithData: response options: NSJSONReadingMutableContainers error: &err];
NSString *result = [jsonArray valueForKey:#"result"];
NSLog(#"%#",result);
if ([result isEqual:#"success"]) {
The log shows "result" is getting set as "success", but it never seems to evaluate as true.
If I set "result" manually:
NSString *result = #"success";
...it gets into the if statement just fine, so it seems like there's something I'm missing that's pointing to a data type or something similar... I'm just at a loss of what else to try at this point.
I'm normally a web dev, but I'm new to iOS, so my debugging is still a little lacking in xcode but I'm familiar with general logic and such. Any help you guys could give me would be fantastic!
Edit:
NSLog showing the JSON coming back from the webservice:
2014-01-10 16:22:42.568 LoginTest[1640:70b] (
{
code = 1;
fname = Joe;
lname = Tests;
result = success;
token = 2555f13bce42b14cdc9e60b923bb2b20;
vendornum = 50000000;
}
)
Edit - final working code:
NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData: response options: NSJSONReadingMutableContainers error: &err];
NSLog(#"jsonArray: %#", jsonArray);
NSString *result = [jsonArray[0] objectForKey:#"result"];
NSLog(#"%#",result);
if ([result isEqual:#"success"]) {

Earlier you commented (from a now removed answer) that -isEqualToString: threw an unrecognized selector. I believe it was -[__NSCFArray -isEqualToString:] or something very similar.
Based on your comment, you don't have "success", you have [ "success" ] in your JSON.
That is an array which wraps the value of a string. You need to get the first element of the array and use that.
[result[0] isEqual:#"success"]
Based on the output in your log, your JSON is not an object
{
…
"result" = "success"
…
}
It is an array with only one object in it.
[
{
…
"result" = "success"
…
}
]
You are working with an array of data so the output of -valueForKey: will be an array of data.
#MartinR is correct, it may be clearer to use
[jsonArray[0] objectForKey:#"result"]
to get the result.

You didn't show us the actual output of the log. That's bad. Deducing from your comments, it should have shown something like
(
"success"
)
which is the description of an array object (NSArray) containing a string, rather than the string object itself.
If this is indeed the case, then you need to get the (only? first?) element in the array and compare that using isEqual: or isEqualToString:.

if we want to compare two NSString we use [str1 isEqualToString:str2]; You should do same instead of isEqual:
isEqual: compares a string to an object, and will return NO if the object is not a string. do it if you are not sure if object is NSString.
`isEqualToString:` use it when you are sure both Objects are NSString.

Related

How to include null value in the JSON via NSJSONSerialization?

I think I get it how to use the NSJSONSerialization over all. The call I am making is:
[NSJSONSerialization dataWithJSONObject:parameters options:0 error:&error]
where parameters is a NSDictionary which includes keys and values to use in the JSON request. Everything is fine and all, until I have to use null as a value instead of an empty string. I can't find a way to set the value as null at all. The example of json that I need to create is:
{"target"
{"firstname":<firstname>,
"lastname":<lastname>},
"error":null
}
The way server is setup is that it's expecting either an error as a string or a null if there's no error.
Any ideas? Am I missing an API call or something like that?
Thanks!
You have to use NSNull. For instance
Swift
let dict = ["firstKeyHasValue": 2342, "secondKeyHasNoValue": NSNull()]
Objective-C
NSDictionary *dict = #{ #"error": [NSNull null] };
From the official documentation of NSDictionary:
Neither a key nor a value can be nil; if you need to represent a null value in a dictionary, you should use NSNull.
I tried doing this and worked for me.
var param: [String:Any] = [:]
param["firstName"] = "somename"
param["middleName"] = NSNull()
param["lastName"] = "somename"
print(param)
Result:
["firstName":"somename","middleName":null,"lastName":"somename"]
If you are using Swifty JSON, I've just created a PR that should handle nil. It's not merged yet and might need some improvements.
The part that describes how to do that should be a good start to write your own implementation if you need to. The logic is not that complicated but there might be tricky edge cases/performance things to think about.
I know it's not a direct response to the question since it's replacing NSJSONSerialization, but I hope it can help some people frustrated by how Swift handles nil/json!
Just try something like this:
NSDictionary *jsonObj = [NSDictionary dictionaryWithObjectsAndKeys:#"My Name", #"name", #"Developer", #"occupation", NULL, #"My NULL field", nil];
and use this object as parameter where you want it.

Get correct Node Json objective c

I'm parsing a Json object via AFJSONRequestOperation, the problem is, i cant get the correct value of the node.
The Json :
Link
I need to get only the temp value, inside the "results". I can get the results node, but the value inside it come as a array, how i can get the value for the name ?
That JSON is invalid. Go to this link, and check it.
What Snaker answered is pretty accurate, still:
for (NSDictionary *dic in results)
{
NSString *name = [dic objectForKey:#"name"];
}
Your problem here, is that the results gives you a dictionnary of dictionnaries.
So you have to retrieve the dictionnary called "results", and then, once you got all the dictionnaries in it, you look for the names trough a loop.
More information here
UPDATE :
dicionario = [dicionario objectForKey#"results"];
NSMutableArray *namesFromDict = [[NSMutableArray alloc] init];
for (NSDictionary *elts in dicionario)
{
[namesFromDict addObject:[elts objectForKey:#"name"]];
}
This should do.

iOS - exception when checking if string is empty

I am doing something like this:
// GET THE USER ID
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *user_id = [standardUserDefaults objectForKey:#"user_id"];
And then checking whether the user_id is empty
if ([user_id length] == 0) {
proceed = false;
NSLog(#"Error: User id is not set.");
}
And I get this runtime exception:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFBoolean length]: unrecognized selector sent to instance 0x1469f70'
Any idea why I get the exception? I didn't think there was anything too wrong with what I was doing.
Thanks!
This:
NSString *user_id = [standardUserDefaults objectForKey:#"user_id"];
Is returning an NSNumber (as NSCFBoolean is a private subclass of NSNumber) rather than a string. It therefore doesn't implement length, causing the exception.
Perhaps you want to test [user_id intValue] > 0? Even if you convert it to a string it'll always have some length.
(side issues raised: merely declaring user_id as a reference to an NSString doesn't mean that anything you assign to it magically becomes a string; indeed there are no type object-type coercion effects whatsoever. The compiler doesn't complain because the NSUserDefaults return objects of type id, i.e. it guarantees they're objects but makes no claims as to their type, and the compiler doesn't know either. All objects may be cast to and from id without generating a warning, so that it can be used by classes such as the user defaults, NSArray, etc, where they can accept anything as long as it's an object).
EDIT: based on issues raised in the comments, it sounds like the thing originally being stored may not be a string. A good way to validate web stuff is probably something like:
// fall through here if the object isn't a string
if(![responseString isKindOfClass:[NSString class]])
{
// check whether it's something that can be converted to a string
if(![responseString respondsToSelector:#selector(stringValue)])
{
// some sort of error condition; the server returned something
// that isn't a string and doesn't convert (in and of itself) to string
}
else
{
// convert the object to a string
responseString = [responseString stringValue];
}
}
The reason you are getting that error is you are trying to call 'length' on what appears to be a boolean. Either way, for checking if a string is blank here are some easy methods you can add to the NSString class by means of a category:
-(BOOL)isBlank{
return [[self trim] length]==0;
}
-(NSString *)trim{
return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet] ];
}
Then to call it it's just:
[myString isBlank];

if statement for dictionary objectforkey:#"key" when value is <null>

I am working with objective c for an iphone app.
I see that [dictionary objectForKey:#"key"] return <null>. Doing a if([dictionary objectForKey:#"key"] == nil || [dictionary objectForKey:#"key"] == null) does not seem to catch this case.
Doing a if([[dictionary objectForKey:#"key"] isEqualToString:#"<null>"]) causes my program to crash.
What is the correct expression to catch <null>?
More Details
An if statement for nil still isn't catching the case... Maybe i'm just too tired to see something, but here's additional info:
Dictionary is populated via a url that contains json data like so:
NSURL *url = [NSURL URLWithString:"http://site.com/"];
dataresult = [NSData dataWithContentsOfURL:url];
NSError *error;
NSMutableDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:dataresult options:kNilOptions error:& error];
doing an NSLog on the dictionary gives this output:
{
key = "<null>";
responseMessage = "The email / registration code combination is incorrect";
}
You have an instance of NSNull. Actually, the instance, since it's a singleton.
Cocoa collections can't contain nil, although they may return nil if you try to access something which isn't present.
However, sometimes it's valuable for a program to store a thing meaning "nothing" in a collection. That's what NSNull is for.
As it happens, JSON can represent null objects. So, when converting JSON to a Cocoa collection, those null objects get translated into the NSNull object.
When Cocoa formats a string with a "%#" specifier, a nil value will get formatted as "(null)" with parentheses. An NSNull value will get formatted as "<null>" with angle brackets.
New answer:
Thanks for adding the detail. It looks like the "dataresult" you are setting is not a JSON object so no wonder you're getting wacky results from putting a raw string into "[NSJSONSerialization JSONObjectWithData:]. You may need to do some basic error checking on your data before you call anything JSON related.
Original answer:
First off, if this were my code, I wouldn't name a "NSDictionary" object "array" (and I see you caught my comment in your edit... hope you get some sleep soon!).
Secondly, what you are looking for is "nil", not a string named "<null>". As Apple's documentation for objectForKey: states, if an object is not found for the key you are asking for, a nil is returned. The Xcode console tries to be helpful in converting nil objects to "<null>" strings in it's output.
Do "if [dictionary objectForKey: #"key"] != nil" and you should be happier.
Just use the following code:
if ([[dictionary valueForKey:#"key"] isKindOfClass:[NSNull Class]]{
//This means that the value inside the dictionary is <null>
}
else{
//the value is not <null>
}
This should do it.

NSDictionary objectForKey return value

I'm using json-framework to create a NSDictionary out of a JSON response. That much works wonderfully.
Now, within this JSON payload are one or more objects - let's call them X. Sort of like this in XML:
<OBJECTS>
<X>
...
</x>
<X>
...
</X>
<X>
...
</X>
</OBJECTS>
When I look in the aforementioned NSDictionary object for all Xs, like so:
NSDictionary *results = [[dict objectForKey:#"OBJECTS"] objectForKey:#"X"];
Or even:
NSDictionary *results = [dict valueForKeyPath:#"OBJECTS.X"];
I get, according to gdb, a NSCFArray of NSDictionary objects. (Yes, I smell something funny here too, but more on this in a moment.)
When there is only one object named X, I get back an honest-to-goodness NSDictionary.
So ... what should I do to make this behave consistently, no matter how many Xs there are?
At first glance, I'd think I just change results to be NSArray *, but what happens when I want to fast enumerate over the results? Right now I do this:
for (NSDictionary *result in results)
In the NSCFArray case (multiple Xs), I get back an individual NSDictionary for each X. In the single X case, I get back the one NSDictionary, except now my perspective is one level too deep. In other words, instead of this (contrived example):
(gdb) po results
<NSCFArray 0xd4a940>(
{
foo = {
bar = "something";
};
}
{
foo = {
bar = "something else";
};
}
)
I get this:
(gdb) po results
{
foo = {
bar = "something";
};
}
Clues welcome/appreciated! You may even ask if it's necessary to have to break this apart at all, but for now let's suppose this trip is really necessary. (Still, I'm happy to be persuaded otherwise, if someone feels strongly enough about it.)
Ultimately, at the end of the day, I want to have a NSArray of NSDictionary objects.
I am not familiar with JSON or the json-framework, but clearly objectForKey cannot be used to access the X's since they all have the same key.
If you know that objectForKey:#"OBJECTS" will return either an NSDictionary (single element) or an NSArray of NSDictionarys (multiple X elements), then you could do something like:
if ( ![results isKindOfClass:[NSArray class]] ) {
results =[NSArray arrayWithObject:results];
}
That will get you a consistent result, assuming you understand exactly how the json-framework will behave. It will be somewhat fragile, if the elements ever return an array of entries instead of an NSDitionary then it will all fall apart.
There may be a configuration setting for the json-framework that lets you control how it behaves in this case and that would be preferable.
NSDictionary *results = [[dict objectForKey:#"OBJECTS"] objectForKey:#"X"];
and
NSDictionary *results = [dict valueForKeyPath:#"OBJECTS.X"];
The above two are exactly same. The first operation is a little costlier operation than the second one.
Here's what I ended up doing:
// Get the JSON response and return the result:
NSString *jsonString = [NSString stringWithContentsOfURL:url];
NSDictionary *dict = [jsonString JSONValue];
// If OBJECTS.X gets a dictionary (one value), make an array of one.
id myObject = [dict valueForKeyPath:#"OBJECTS.X"];
if ([myObject isKindOfClass:[NSDictionary class]]) {
results = [NSArray arrayWithObject:myObject];
} else {
results = myObject;
}
It's worth pointing out that JSONValue can also return a dictionary or an array. However, I'm looking inside the dictionary post-assignment (OBJECTS.X).
I don't think your two code examples,
NSDictionary *results = [[dict objectForKey:#"OBJECTS"] objectForKey:#"X"];
and
NSDictionary *results = [dict valueForKeyPath:#"OBJECTS.X"];
are equivalent. Key-Value-Coding has some extra smarts to work with collections, which might be throwing you off here. (An example can be found in the blog post Theocacao: NSArray and KVC by Scott Stevenson.)
If you revert back to the former you might get the behaviour you expect.