How to parse JSON using AFNetworking in iOS? - ios

I am using AFNetworking framework in my app, I am able to make HTTP request and able to get response from server but i am not able to parse the JSON.
The following is my code:
I have created a singleton class called WebServices and have created a method, which makes HTTP request.
+(void)getCompaniesc:(NSString *)companyID onSucess:(PSACompletionBlock2)onSucess
{
NSDictionary *params = #{#"companyId": companyID};
[[[WebServices sharedInstance] operationQueue] cancelAllOperations];
[[WebServices sharedInstance] postPath:#"GetCompany?" parameters:params success:^(AFHTTPRequestOperation *operation, id response)
{
NSString *st = [NSString stringWithFormat:#"%#",response];
NSLog(#"st=%#",st);
if (onSucess)
{
onSucess(YES, response);
}
}failure:^(AFHTTPRequestOperation *operation, NSError *error){
NSLog(#"%s: AFHTTPRequestOperation error: %#", __FUNCTION__, error);
}];
}
and from my ViewController I am calling the above function using the following code:
[WebServicesClass getCompaniesc:companyID onSucess:^(BOOL success, id jsonresponse) {
}];
I'm getting the response from the server which is type id.
And the following is my response from Server:
[{"ExistsInDB":"False","CanSave":"True","EntityName":"ACCOUNT","TypeDescription":"Company","TypePluralDescription":"Companies","RequiredProperties":"Chiever.Data.SAQueryFieldSet","MetaData":"","ReadOnly":"False","ACCTNAME":"","AREA_ID": "","ACCT_TYPE_ID":"","ADDR1":"","ADDR2":"","ADDR3":"","TOWN”:””,”COUNTY":"","POSTCODE":"","COUNTRY":"","TEL":"","FAX":"","EMAILORWEB":"","BUYGRP_ID": "","STATUS":"","SIC_CODE_ID”:””,”CURRENCY_ID":"","CALL_FREQ": "0","DORMANT":"False","CREATOR_ID": "","CREATED_ON":"01/01/0001 00:00:00","LAST_EDITOR_ID":"","LAST_EDITED":"01/01/0001 00:00:00","LAST_ACTION_BY":"","LAST_ACTION":"01/01/0001 00:00:00","NEXT_ACTION_BY":"","NEXT_ACTION":"01/01/0001 00:00:00","LOCALE_ID":"","BusinessUnits": "System.Collections.Generic.List`1[chiever.Platform.LookupIdValuePair]","ACCT_ID":"0000000320"}]
Can any one help me out with this?

Just do this check:
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData: jsonresponse options:NSJSONReadingMutableContainers error:&error];
if your return is an array, use this:
NSArray *arr = [NSJSONSerialization JSONObjectWithData: jsonresponse options:NSJSONReadingMutableContainers error:&error];

A.) If you're using AFHTTPRequestOperation make sure you're setting the responseSerializer:
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
operation.responseSerializer = [AFJSONParserResponseSerializer serializer];
Also, make sure that you're setting request "Content-Type" to be "text/json". Now, if you're getting JSON response from the server, then you probably should get a dictionary responseObject.
B.) If you're still getting an NSData, you can convert the NSData to NSString to see/debug what you're getting from the server:
NSString *stringResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; // Use appropriate encoding
NSLog(#"String Response: %#", stringResponse);
C.) If you're sure that you're getting json response from the server, you can always convert the raw NSData response to NSDictionary using json serialization:
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"JSON: %#", json);
Hope this helps.

If your server returns the "Content-Type: application/json" header, you will get a NSDictionary with the json response from AFNetworking. Or in your case, a NSArray with NSDictionaries included.
In PHP, the headers can be modified by adding
header('Content-Type: application/json');
to the top of your script.

Related

Error while hitting a API

I am hitting a API for push notification and it is giving me error.
I am passing parameter as a string in API like this:
NSString * jsonString= [NSString stringWithFormat:#"{\"device_id\":%#,\"device_type\":I,\"regId\":%#}",[AppDelega‌​te getMacAddress],deviceToken];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager POST:kNotificationURL
parameters:jsonString
progress:nil
success:^(NSURLSessionTask *task, id responseObject) {
NSLog(#"notification JSON: %#", responseObject);
NSDictionary *json = [Utility cleanJsonToObject:responseObject];
NSError * err;
NSData * jsonData = [NSJSONSerialization dataWithJSONObject:json
options:0
error:&err];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:jsonData
options:kNilOptions
error:&err];
NSLog(#"the data is %#",dict);
}
failure:^(NSURLSessionTask *operation, NSError *error) {
NSLog(#" notification Error: %#", error);
}];
The error I am getting:
Response :Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.}
please let me know, what have i do wrong
A quick and dirty fix would be to try this, although building your own JSON string isn't a good idea. Look at using JSONSerialization
[NSString stringWithFormat:#"{\"device_id\":\"%#\",\"device_type\":\"I\",\"regId\":\"%#\"}",[AppDelega‌​te getMacAddress],deviceToken];

jsonObjectWithData causing memory crash?

I am getting response data from a server using AFHTTPRequestOperation in AfNetworking 2.0
NSURLRequest *request = [[ServiceHelper instance] getRequestData:postDict :[ServicesConfiguration GET_DOCUMENTS_URL]];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
AFHTTPRequestOperation *requestOperation = [manager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSDictionary *returnData = [[ServiceHelper instance] getReturnDictionary:responseObject];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
The getReturnDictionary method called on the responseObject is a simple JSON Serializer..
- (NSDictionary *) getReturnDictionary : (NSData *) data {
if ( data == nil ) {
return [NSDictionary dictionary];
}
NSError * error = nil;
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if (error != nil) {
NSLog(#"Error parsing JSON: %#",error);
return [NSDictionary dictionary];
}
else
return jsonDict;
}
This works fine for smaller amounts of data. But when the response object is like 100mb, the app hangs on
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
And then about 15 seconds later, the app crashes due to a memory error.
I think its pretty self explanatory that its the massive size of the data, but shouldn't it be able to handle it?
If I get the data directly from an [ NSURLConnection sendSynchronousRequest:]; - it works without hanging or crashing. As this is what I was doing originally - but switching to AFNetworking to display a progress bar more easily.
Any thoughts or tips are appreciated.
Update:
So You have 2 options to solve this:
Blockquote
Use NSJSONReadingMutableContainers as options
Blockquote
If previous does not work you are facing a known issue like below:
iOS Download & Parsing Large JSON responses is causing CFData (store) leaks
So now you have 2 options:
Use native JSON Serialization
First downloading the JSON files to disk without using AFNetworking and than parse.

AFNetworking GET request - unable convert responseObject to NSDictionary

I have tried several option setting responseSerializer to JSON but i am unable to convert responseObject to NSDictionary. The problem is response i am getting is NSData
NSString *baseURLString = #"Your URL?";
NSString *str = #"adult=false&gender=male";
NSString *url = [NSString stringWithFormat:#"%#%#",baseURLString,str];
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
[manager GET:url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
// do whatever you'd like here; for example, if you want to convert
// it to a string and log it, you might do something like:
NSLog(#"responseObject %#",responseObject);
NSString *jsonString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"%#", jsonString);
NSError* error;
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:responseObject
options:NSJSONReadingMutableContainers
error:&error];
NSLog(#"json %#",json);
if (error) {
NSLog(#"%#",[error description]);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
This NSLog(#"%#",[error description]); gives error as follows:
Error Domain=NSCocoaErrorDomain Code=3840 "The operation couldn’t be completed.
(Cocoa error 3840.)" (Garbage at end.)
UserInfo=0xa7c5440 {NSDebugDescription=Garbage at end.}
Your JSON is coming back with garbage at the end.
You should fix your webservice to not embed timestamp and language at the end of your JSON. If you can not change your webservice, then use following to remove trailing garbage from your json before parsing it with NSJSONSerialization again.
NSRange range = [jsonString rangeOfString:#"}" options:NSBackwardsSearch];
jsonString = [jsonString substringToIndex:range.location + 1];
Then parse this cleaned up jsonString to NSDictionary:
NSData *newJSONData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary* json = [NSJSONSerialization
JSONObjectWithData:newJSONData
options:NSJSONReadingMutableContainers
error:&error];
NSLog(#"json %#",json);
It should work just fine.
Your data is not a valid JSON you can check in this JSON Formatter provide the url or copy paste the JSON data and hit process you will see that its not a valid JSON.
The reason it not valid is it contains This page was created in 0.0048439502716064 seconds this message at the end of its response. If have control in the server side than try to stop sending this line in the end or try to remove this line and the convert it to NSDictionary. Hope this helps .. :)

How do I make my AFNetworking "responseObject" that I receive a NSDictionary I can parse?

I have this call with AFNetworking 1.0 that returns a responseObject with the data from the API that I want:
[[AFDiffbotClient sharedClient] postPath:#"http://diffbot.com/api/batch" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
However, I have no idea how to process responseObject.
If I check [responseObject class] I get NSData.
If I NSLog(#"%#", responseObject) I get a bunch of numbers (memory addresses I assume):
<5b0a7b22 68656164 65727322 3a5b7b22 6e616d65 223a6e75 6c6c2c22 76616c75 65223a22 48545450 2f312e31 20323030 204f4b22 7d2c7b22 6e616d65 223a2244 61746522 2c227661 ...
If I do:
NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
NSLog(#"%#", responseString);
I get the output that I want! But, it's an NSString.
If I do:
NSError *error;
NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseObject options:kNilOptions error:&error];
NSLog(#"%#", responseDictionary);
I get an NSDictionary, but it's missing the vast majority of the response (i.e.: I don't get what's included with the NSString method).
How should I be processing this object?
This is how I do it..
- (void) requestDataFinish:(NSData *)data withError:(NSError *)networkError
{
NSDictionary *responseData;
NSError *error = nil;
if (data != nil) {
responseData = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&error];
}
...

AFNetworking: Can't get the response string from AFHTTPRequestOperation

Anyone?): I'm having a problem that has made me scratch my head for the last 2 hours, and it most likely a very simple stupid thing I'm missing. I Keep getting a building error when I Call the response string from the operation # AFNetworking... Like there is NO SUCH PROPERTY....
Please Take a look at my code and Explain me what did I Mess up This time :p.. THanks :)
NSDictionary* paramDict = [NSDictionary dictionaryWithObjectsAndKeys:WebServicemd5Value, WebSermd5Variable, nil]
;
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:webServiceURL]];
[httpClient defaultValueForHeader:#"Accept"];
[httpClient postPath:#"method" parameters:paramDict success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Response data: %#", responseObject);
NSLog(#"Reponse String: %#", operation);
// Printing operation will show me the operation Dictionary, including the reponse field, // but when I Directly call operation.response, the Compiler won't Build, stating that // "Property not found for AFHTTPRequestOperation".... WEIRDEST THING EVER, right?
NSString* responseString = [NSString stringWithUTF8String:[responseObject bytes]];
//.. Rest o f my Code....
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", error);
}];
Hernan, if you expect an NSDictionary from a JSON response you should consider using AFJSONRequestOperation, because you get a JSON dictionary in your success callback. Anyway, if you want to get a dictionary from your responseObject, try to use the following code:
NSError *error = nil;
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:responseObject options:NSJSONReadingAllowFragments error:&error];
if (error) {
NSLog(#"Error serializing %#", error);
}
NSLog(#"Dictionary %#", JSON);
I believe the response string is inside the "operation" object, so something like:
...
}failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error retrieving data: %#", operation.responseString);
}];
While attempting to retrieve content from meetup.com api using AFNetworking (kudos to Mattt T. for a great framework, btw), ran into the same error - "The operation couldn't be completed. (Cocoa error 3840)". Realized that the issue I was having was with the response data containing a Swedish character 'Ø', resulting in the parsing error. The solution was to include the header 'Accept-Charset: utf-8' in the initialization of the AFNetworking client. Fixed!
- (id)initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (!self) {
return nil;
}
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
// Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
[self setDefaultHeader:#"Accept" value:#"application/json"];
[self setDefaultHeader:#"Accept-Charset" value:#"utf-8"];
return self;
}

Resources