jsonObjectWithData causing memory crash? - ios

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.

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.

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];

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 to parse JSON using AFNetworking in 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.

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