Parsing JSON with AFNetworking into NSDictionary - ios

I am trying to parse some JSON with AFNetworking and an NSDictionary. However something seems strange with the JSON. The JSON contains routes for shuttles, but I do not see a 'route' in the JSON.
When I run this code I get an empty NSDictionary with 15 allocated spaces.
NSString *methodURL = [NSString stringWithFormat:#"%#GetRoutesForMapWithSchedule", BASE_URL];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:methodURL parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
_routes = (NSDictionary *)responseObject;
//_route = _routes[#"Stops"];
NSLog(#"JSON: %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
Can anyone explain how I can get all the info for one route? This is the JSON.
NSArray *routes = (NSArray *)responseObject;
NSDictionary *oneRoute = responseObject[0];
NSDictionary *stops = oneRoute[#"Stops"];

The problem is that the top level JSON object is actually an array, not a dictionary as you're trying to cast it to. Each element of the array on the other hand, is a dictionary.
Here is some code to get the general data structure and to get a piece of data out of one of the routes.
NSArray *routes = (NSArray *)responseObject;
NSDictionary *firstRoute = responseObject[0];
NSString *description = firstRoute[#"Description"];
Edit: To parse Stops, you would do something like this:
NSArray *stops = firstRoute[#"Stops"];
NSDictionary *firstStop = stops[0];
NSString *stopDescription = firstStop[#"Description"];

Related

Cant parse afnetworking json response to nsdictionary

I am attempting to call an external API with the following afnetworking request code:
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
destination, #"destination",
nil];
[manager POST:baseUrl parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
completion(nil, responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
completion(error, nil);
NSLog(#"error: %#", error);
}];
When I print out the responseObject I get the following which is the json that I expect to see:
However when I attempt to access the code e.g. responseObject[#"code"] I get some strange text:
(__NSCFNumber *) $0 = 0xb00000000000fa33 (long)4003
I then tried to parse this with NSStringwithformat %ld, but that returns:
(__NSCFString *) $1 = 0x000060800005a850 #"-5764607523034170829"
Not sure what's going on here, whether the responseObject has even been parsed properly as an NSDictionary
any help would be appreciated
i'm not sure what is going on here, but I recommend to use Gloss framework for JSON Serializing/Deserializing to map JSON on objects directly.
http://harlankellaway.com/Gloss/
i'm not sure what is happening but it's strange
so i suggest you can Debug it step by step
What i suppose is that the number is a float, try
NSNumber *num = [responseObject objectForKey:#"code"];
int theValue = [num intValue];
This might help.
so what you have to do is, inside you success block,
NSDictionary *result = (NSDictionary *)responseObject;
for(NSDictionary *all in result){
int code = [all objectForKey:#"code"];
}
hope this will help to your.
note : better to use model and add those objects to a mutable array.

Using AFHTTPRequestOperation to construct URL (curly braces included)

I need to construct URL like this using AFNetworking the problem for me it's { and } how to pass throught parameter
/api/sth.json?filter[condition]={"53891":[123],"53892":[123,124]}
So my code looks like this (i made it simpler):
[self GET:myUrl parameters:#{
#"filter" : #{
#"condition" : #{
#"53891" : #[#(123)],
#"53892" : #[#(123),#(124)]}
},
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
success(operation,responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure(operation,error);
}];
But it's produce not expected output:
/api/sth.json?filter[condition][53891][]=123&filter[condition][53892][]=123&filter[condition][53892][]=124
There is a way to do this in parameters in AFHTTPRequestOperation or manually i have to put it into string?
EDIT:
My current solution is like that:
+(NSString*)convertFromDictionary:(NSDictionary*)dic {
NSMutableString *outputStr = [NSMutableString new];
[outputStr appendString:#"{"];
NSArray *allKeys = [[dic allKeys] sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:nil ascending:NO]]];
for(NSString *key in allKeys) {
NSArray *objects = dic[key];
[outputStr appendString:[NSString stringWithFormat:#"\"%#\":[",key]];
for(NSNumber *nb in objects) {
[outputStr appendString:[NSString stringWithFormat:#"%li",[nb longValue]]];
if(![nb isEqual:[objects lastObject]]) {
[outputStr appendString:#","];
} else {
[outputStr appendString:#"]"];
}
}
if(![key isEqual:[allKeys lastObject]]) {
[outputStr appendString:#","];
}
}
[outputStr appendString:#"}"];
return outputStr;
}
Where input dictionary is:
#{#"53892" : #[#(123),#(124)]}
But it's nothing more than string compare. There is no more clever way to achieve it with AFNetworking directly since it's fairly standard URLs parameters?
You want 2 different ways of parsing a dictionary, and this cannot be done automatically. As Mehul said before, try serializing your parameter "condition" (converting its value to string) before creating the "parameters" dictionary:
NSError *error;
NSDictionary *dict = #{#"53891" : #[#(123)], #"53892" : #[#(123),#(124)]};
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error];
NSString *params = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
[self GET:myUrl parameters:#{
#"filter" : #{
#"condition" : params
},
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
success(operation,responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
failure(operation,error);
}];
You need to do this:
create dictionary
create json string from dictionary(first convert dictionary to NSData using NSJsonSerialization and then convert thata NSData object to NSString)
Now append this string in your URL in format which you want to attach to
create url from new string and pass it in get/post method with paramters dictionary as nil
Wrapping a numbers with parenthesis is for expressions :
#(6 + x * 2012)
Read excellent explanation post https://stackoverflow.com/a/9349981/3096087
Maybe wrapping in parenthesis somehow messes up with AFHTTPRequestOperation.
NSNumber are directly declared the following way :
NSNumber *number = #123;
So try with an input dictionary the following way :
#{#"53892" : #[#123,#124]}

afnetworking get json data out from response

I am trying to extract data(just a string) from request and set it to the NSString. I tried it in many way but it is not working. If anyone can point out my mistake, it will be very helpful for me.
json data
{
"status": 1,
"key": "1e39248f4a5e05153dc376a"
}
My code
NSString *key;
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *params = # {#"app_token" :APP_TOKEN};
[manager POST:GET_USER_KEY_URL parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary* response = (NSDictionary*) responseObject;
key=[response valueForKey:#"key"];
[[NSUserDefaults standardUserDefaults]setValue:(key) forKey:USER_KEY];
NSLog(#"NEW KEY Request: %#", key);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"NEW KEY Request error: %#", error);
}];
Just want to assign response "key" data and store it on the NSString *key;
Thank you in advance.
You have declared the variable key outside of the block. You need to add __block infront of NSString *key;
To assign a variable outside a block you have to remember the __block specifier.
Related question:
Assign a variable inside a Block to a variable outside a Block

Issue with AFNetworking

My client webservice send me a result like this:
{"login":{"EMAIL":"none","ID":"none","NOME":"none"}}
So, in AFN doesn't work.
But, if have one more result works:
{"login":[{"EMAIL":"none","ID":"none","NOME":"none"},{"EMAIL":"none","ID":"none","NOME":"none"}]}
My code:
NSDictionary *paramLogin = [NSDictionary dictionaryWithObjectsAndKeys:_txtEmail.text, #"email",_txtSenha.text, #"senha", nil];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:#"http://webservice.info" parameters:paramLogin success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"%#" , responseObject );
for (NSDictionary *retLogin in [responseObject valueForKeyPath:#"login"]) {
nome = [retLogin objectForKey:#"nome"];
email = [retLogin objectForKey:#"email"];
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
why it is like this? or what I've to do ?
Sometimes [responseObject valueForKeyPath:#"login"] returns and array, sometimes it returns a dictionary. You need to test for this.
id loginValue = [responseObject valueForKeyPath:#"login"];
if ([loginValue isKindOfClass:[NSDictionary class]]) {
nome = [loginValue objectForKey:#"nome"];
email = [loginValue objectForKey:#"email"];
} else if ([loginValue isKindOfClass:[NSArray class]]) {
for (NSDictionary *retLogin in [responseObject valueForKeyPath:#"login"]) {
nome = [retLogin objectForKey:#"nome"];
email = [retLogin objectForKey:#"email"];
}
} else {
// ERROR: Unexpected value
}
When you have 1 value, then loginValue is an NSDictionary. It contains {"EMAIL":"none","ID":"none","NOME":"none"}.
When you have more than 1 value, then loginValue is an NSArray. The array contains [<NSDictionary>, <NSDictionary>]. Each of of these dictionaries contains {"EMAIL":"none","ID":"none","NOME":"none"}.
Problem is with your json data structure. It's not consistent.
{"login":{"EMAIL":"none","ID":"none","NOME":"none"}}
Here [responseObject valueForKeyPath:#"login"] is a single NSDictionary object.
But here,
{"login":[{"EMAIL":"none","ID":"none","NOME":"none"},{"EMAIL":"none","ID":"none","NOME":"none"}]}
Here [responseObject valueForKeyPath:#"login"] is an NSArray. So your fast enumeration works.
Best solution is to ask your webservice developer to send an array all the time, even 'login' has a single object. so it should look like this,
{"login": [{"EMAIL":"none","ID":"none","NOME":"none"}]} //notice square brackets
Otherwise you have to modify your code to check for an NSDictionary instead of array when there's only one object.
I suspect the issue is that you aren't retaining the AFHTTPRequestOperationManager object.
Assuming this code is in something like viewDidAppear:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager GET:...];
Then manager will be destroyed before it has a chance to complete.
Instead add a property and store the manager object in that:
#interface MyViewController ()
#property (nonatomic) AFHTTPRequestOperationManager *manager;
#end
and use:
self.manager = [AFHTTPRequestOperationManager manager];
[self.manager GET:...];
if you are getting response like that than use below code
NSMutableArray *category = [[NSMutableArray alloc]init];
category = [responseObject objectForKey:#"login"];
for(int i = 0; i < [category count]; i++)
{
NSDictionary *dic = [category objectAtIndex:i];
nome = [dic objectForKey:#"nome"];
email = [dic objectForKey:#"email"];
}

AFHTTPRequestOperationManager JSON data to Array

I'm using AFNetworking 2.0 to make a POST request to my web service that returns JSON data.
{
post = {
"first_name" = Joe;
"last_name" = Blogs;
"user_id" = 1;
};
},
{
post = {
"first_name" = Bill;
"last_name" = Gates;
"user_id" = 2;
};
}
Im able to print out responseObject to the console fine which displays my JSON data.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"user": #"root"};
[manager POST:#"http://192.168.0.100/webservice.php" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject)
{
NSString *responseString = [operation responseString];
NSError *error;
NSArray *json = [NSJSONSerialization
JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding]
options:kNilOptions
error:&error];
for (NSDictionary *dictionary in json)
{
NSString *firstName = [[dictionary objectForKey:#"post"] valueForKey:#"first_name"];
NSLog(#"%#", firstName);
NSString *lastName = [[dictionary objectForKey:#"post"] valueForKey:#"last_name"];
NSLog(#"%#", lastName);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}];
Each "post" is going to be used for a table cell on my View Controller. Im struggling to understand how to make each post an object in an array. Any help appriciated.
UPDATE
You can use this code snipped to perform your desired functionality:
NSString *responseString = [operation responseString];
NSData *data= [responseString dataUsingEncoding:NSUTF8StringEncoding];
NSError *error;
NSArray* results = [NSJSONSerialization JSONObjectWithData:data
options:0
error:&error];
for (int i=0; i<results.count; i++)
{
NSDictionary *res=[results objectAtIndex:i];
NSDictionary *res2=[res objectForKey:#"post"];
[self.storesArray addObject:res2];
}
[self.tableView reloadData];
and in your CellForRowAtIndexPath method, use this code snipped to show data on your cell:
NSDictionary *res=[self.storesArray objectAtIndex:indexPath.row];
cell.firstName.text=[res objectForKey:#"first_name"];
cell.lastName.text=[res objectForKey:#"last_name"];
This NSDictionary works in key values pair style, so you can get the value of any key by just mentioning the key name and get the values of that key.

Resources