AFNetworking request fails when embedding a NSArray inside a NSDictionary - ios

So, basically I am trying to make a JSON Request against a WS in which one of its parameter is an Array using AFNetworking 3.0 My Json should look something like:
{
"filtrosAlerta": [
{
"data": "",
"type": ""
}
],
"frecuency": 0
}
The backend error doesn't say much really (Request failed: internal server error (500)) but after troubleshooting this in different ways, the Array inside the Dictionary seems to be the problem. So I am sending the following request through AFNetworking 3.0:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFJSONRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
manager.requestSerializer = serializer;
[manager.requestSerializer setAuthorizationHeaderFieldWithCredential:credential];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:#"application/json", #"text/json", #"text/javascript", #"text/html",nil];
NSString *url = #"http://www.example.com/webservice"
NSArray *filters = #[#{#"data" : #"java", #"type" :#"query"}, #{#"data" : #"29", #"type" :#"provincia"}];
NSDictionary *parameters = #{#"filtrosAlerta":filters, #"frecuenciaNotif":[NSNumber numberWithInt:0]]
[manager POST:url parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nullable task, id response) {
completionBlock(response, nil);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
completionBlock(nil, error);
}];
My problem is that when I add the NSArray inside the NSDictionary I get an error from the backend server. If I try to debug the "parameters" NSDictionary inside xcode I get the following thing:
{filtrosAlerta = ({data = java;type = query;}{data = 29;type = provincia;});
frecuenciaNotif = 7;}
Please note that instead of the normal "[]" Json Array I seem to be getting a "()" array which doesn't seem to be right, but this is really xcode debugger, and I believe that eventually AFNetworking will get each object inside the NSDictionary and create the proper JSON string! I've been looking around and tried different answers but could not get this working yet.

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.

Retrieving multiple users from Parse via REST API and using only one AFNetworking request

I need to retrieve multiple users from Parse.com, via their REST API, and using AFNetworking. I need to retrieve these users using one single API call.
The following code is able to fetch one user. You will notice that I am including one objectId because I am only fetching one user. I need to modify this code so that I can call for multiple objectId's and as a result, retrieve multiple users:
//Setup request manager
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setValue:ApplicationId forHTTPHeaderField:#"X-Parse-Application-Id"];
[manager.requestSerializer setValue:APIKey forHTTPHeaderField:#"X-Parse-REST-API-Key"];
[manager.requestSerializer setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSDictionary *query = #{#"objectId":#"cbfG5dFJy7"};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:query
options:0
error:&error];
if (!jsonData) {
NSLog(#"Error: %#", [error localizedDescription]);
}
NSString *dateQueryString = [[NSString alloc] initWithData:jsonData
encoding:NSUTF8StringEncoding];
NSDictionary *parameters = #{#"where": dateQueryString};
//Perform request
[manager GET:[NSString stringWithFormat:#"%#users", BaseURLString] parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject) {
// Handle success
completion(nil, self.mentors, nil);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// Handle failure
completion(nil, nil, error);
}];
In the Parse.com REST API documentation, it says that you can perform a compound or query to achieve this, and it lists the following in the GET request curl example:
--data-urlencode 'where={"$or":[{"wins":{"$gt":150}},{"wins":{"$lt":5}}]}' \
Unfortunately, I do not know how to translate that into objective-c. Here is the same example only in python if that helps:
params = urllib.urlencode({"where":json.dumps({
"$or": [
{
"wins": {
"$gt": 150
}
},
{
"wins": {
"$lt": 5
}
}
]
})})
I just need to include multiple objectId's in my AFNetworking call, and tell Parse.com that I'll accept results for this objectId, or that objectId, etc. so that Parse.com will return all of those users to me.
You currently have a single dictionary for your query that you convert to JSON
NSDictionary *query = #{#"objectId":#"cbfG5dFJy7"};
The or example you show is a dictionary with a single key, where the value is an array of dictionaries like your current query.
#{#"$or":#[ #{#"objectId":#""} , #{#"objectId":#""} ]}
Once you have built this structure you convert it to JSON and add it to the request as you currently are.

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.

POSTing a nested NSDictionary using AFNetworking 2

Using the Postman extension for Chrome I can successfully POST some JSON. Using Charles to inspect the request, I see that the request data is as follows:
{
"query": {
"term": {
"user_id": "12345"
}
}
}
When I try to construct this same request using AFNetworking 2.4.1, I can see that the data is formatted as:
query[term][user_id]=12345
The server of course returns an error.
What part of the POST request am I getting wrong?
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = #{#"query":#{#"term":#{#"user_id":#"12345"}}};
[manager POST:#"http://someURL" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"SUCCESS %#", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"FAIL: %#", error);
}];
The short answer is:
manager.requestSerializer = [AFJSONRequestSerializer serializer];
From the documentation:
Requests created with requestWithMethod:URLString:parameters: &
multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:
are constructed with a set of default headers using a parameter
serialization specified by this property. By default, this is set to
an instance of AFHTTPRequestSerializer, which serializes query
string parameters for GET, HEAD, and DELETE requests, or
otherwise URL-form-encodes HTTP message bodies.

AFNetworking 2 Response Error (Content type: text/html and not JSON)

After trying nearly every response on the subject, I've come up without a working answer to my problem.
The problem: So I've implemented the uploading portion of my app using AFNetworking 2.0.3 after porting from AFNetworking 1.3:
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock {
NSData* uploadFile = nil;
if ([params objectForKey:#"file"]) {
uploadFile = (NSData*)[params objectForKey:#"file"];
[params removeObjectForKey:#"file"];
}
AFHTTPRequestOperationManager *manager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:#"http://54.204.17.38"]];
manager.responseSerializer = [AFJSONResponseSerializer serilizer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/json"];
AFHTTPRequestOperation *apiRequest = [manager POST:#"/API" parameters:params constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
if (uploadFile) {
[formData appendPartWithFileData:uploadFile name:#"file" fileName:#"photo.jpg" mimeType:#"image/jpeg"];
}
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
completionBlock(responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:#"error"]);
}];
[apiRequest start];
}
The error I get when using this code is "Request failed: unacceptable content-type: text/html" I know you might be wondering if the server is responding with proper JSON, and I have every reason to think it is after inspecting the response headers in my browser that say 'MIME type: application/json'. Also, I am using 'header('Content-type: application/json')' at the top of my API as well (PHP API). Now, if I change the serialization type to 'AFHTTPResponseSerializer' instead of 'AFJSONResponseSerializer', it will not spit out the JSON error, but it will give me a different error (a random unrecognized selector error).
Any thoughts on why I cannot seem to get a JSON response out of this method?
You can set the AFHTTPSessionManager to accept any MIME Type:
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"text/html"];
Got it! So, turns out, unknowingly, although my API was returning valid JSON, matter examining the header response logged on the Xcode side of things (thru NSLog(#"Error: %#", error);), it was actually returning text/HTML because it wasn't actually hitting the correct file, it was getting re-routed by a header somewhere. After explicitly stating the API path to be /API/index.php and not just /API, it started returning the valid JSON! Next, after making sure the response was properly JSON serialized (using requestManager.responseSerializer = [AFJSONResponseSerializer serializer];), the app worked!
Hopefully this helps someone who was having the same issue :)

Resources