JSON serialisation in AFNewtorking is failing - iphone

I am trying to perform GET requests that returns JSON string from a web-service using AFNetworking but I am receiving the following error from AFNetworking 1.3.3
#"JSON text did not start with array or object and option to allow fragments not set."
and here is my JSON which is a valid JSON string , I used many online validators to make sure
"{\"ErrorCode\":0,\"VerCode\":\"8595\"}"
AFNetworking Code that is not working
NSString *urlString = [BASE_URL stringByAppendingString:paramseters];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:BASE_URL]];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"GET"
path:urlString
parameters:nil];
AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSDictionary *jsonDic = (NSDictionary *)JSON;
success(jsonDic);
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
CPError *cpError = [CPError CPErrorWithErrorCode:error.code errorDesc:error.localizedDescription];
failure(cpError);
}];
[operation start];
I was able to parse the JSON into NSDictionary using the below code but I want to be able to use AFNetworking in order to make use of it's built in features , is there a way to make AFNetworking understands my JSON string ?
NSURL *url = [NSURL URLWithString:#"http://103.1.173.60/ims-mobile-wcf/MobileWCF.svc/AddUpdateMobileClient/123123/443da4444/1/1"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120];
[request setHTTPMethod:#"GET"];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(#"%#",connectionError);
NSError *error = nil;
NSString *JSONString = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary *JSONDictionary =
[NSJSONSerialization JSONObjectWithData: [JSONString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
}];

I'll take a stab and say the reason is that the response string appears to be in quotes, if this is the case then the error is very clear - the Fragments option is not set. Do a a global search for "JSONReadingOptions" and you'll find the place in AFNetworking where the response is serialized into a foundation object (in version 1.3 it's AFJsonRequestOperation line 79, it looks like your using 2.0) is basically exactly what you are doing manually. If you do as arturdev suggests and set the reading options to be NSJSONReadingAllowFragments it should work.

Try:
AFJSONRequestOperation *operation = ...
operation.JSONReadingOptions = NSJSONReadingAllowFragments;
[operation start];

This is wrong:
NSError *error = nil;
NSString *JSONString = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
NSDictionary *JSONDictionary =
[NSJSONSerialization JSONObjectWithData: [JSONString dataUsingEncoding:NSUTF8StringEncoding]
options: NSJSONReadingMutableContainers
error: &error];
JSONObjectWithData: does not return an NSString, it returns an object: NSArray or NSDictionary, in your case a NSDictionary
Just use:
NSError *error = nil;
NSDictionary *resultDictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];

Related

How to wait response and parse XML done in afnetworking iOS

I want to wait until server reponse and parse XML done, then call another function. How can i do that? I used this code to send request to server and use NSXMLParser to parse XML response.
NSURL *url1 = [NSURL URLWithString:#"linkserver"];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL: url1] ;
NSDictionary *params1 = #{
#"a" : vd;
#"b" : #"all"
};
NSMutableURLRequest *afRequest = [httpClient requestWithMethod:#"GET" path:nil parameters:params1] ;
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Success");
NSString * parsexmlinput = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
[self parseXMLFile:parsexmlinput];// parse xml
[self getItemFromStatus];// wait to call another function at here???
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
}
];
[httpClient enqueueHTTPRequestOperation:operation];
}
Please give me any suggestion. Thanks much
You have to make your request synchronous.
refer code something like:
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"https://api.twitter.com/1.1/friends/ids.json?"]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
[request setHTTPMethod: #"GET"];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *response1 = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
check this tutorial Ray Wenderlich using AFnetworking.
Using blocks and callbacks
- (IBAction)xmlTapped:(id)sender{
NSString *weatherUrl = [NSString stringWithFormat:#"%#weather.php?format=xml",BaseURLString];
NSURL *url = [NSURL URLWithString:weatherUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFXMLRequestOperation *operation =
[AFXMLRequestOperation XMLParserRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
XMLParser.delegate = self;
[XMLParser setShouldProcessNamespaces:YES];
[XMLParser parse];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {
UIAlertView *av = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[NSString stringWithFormat:#"%#",error]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[av show];
}];
[operation start];
}
You can do it in synchronous way...
NSURLResponse *response = nil;
NSError *error = nil;
NSURL *url = [NSURL URLWithString:urlStr];
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
httpClient.parameterEncoding = AFFormURLParameterEncoding;
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST" path:[url path] parameters:params];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * parsexmlinput = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
if(error) {
errorCallback(error, nil);
} else {
//parse the xml here
}
OR
You can achive it by adding [operation waitUntilFinished],after it's added to the operation queue.Refer this==>Can AFNetworking return data synchronously (inside a block)?
OR
EDIT: In case you don't want to use the AFNetworking library.I prefer this way.
NSString *action_Post =[[NSString alloc] initWithFormat:#"authToken=%#",theMutableString];
NSURL *action_Url =[NSURL URLWithString:#"ur url here"];
NSData *action_PostData = [action_Post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *action_postLength = [NSString stringWithFormat:#"%d", [action_PostData length]];//your parameter to be posted here
NSMutableURLRequest *action_Request = [[NSMutableURLRequest alloc] init];
[action_Request setURL:action_Url];
[action_Request setHTTPMethod:#"POST"];
[action_Request setValue:action_postLength forHTTPHeaderField:#"Content-Length"];
[action_Request setValue:#"application/xml" forHTTPHeaderField:#"Accept"];
//[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[action_Request setHTTPBody:action_PostData];
NSURLResponse *action_response;
NSData *action_Result = [NSURLConnection sendSynchronousRequest:action_Request returningResponse:&action_response error:&error];
if (!action_Result)
{
NSLog(#"Error");
}
else
{
//Parse your xml here
//call ur function
}
Modify it according to your GET/PUT methods.But i suggest you to go for POST method,as it is refered to be as secured one.

-JSONValue failed. Error trace is: in Google currency converter in iPhone

I need live currency rates. I am using a Google API available in the URL
http:://www.google.com/ig/calculator?hl=en&q=1USD=?INR
Whenever am hitting that URL using json parsing, then response data getting nil. I am not getting what is the exact error in that code
#define openexchangeURl #"http://www.google.com/ig/calculator?hl=en&q=1USD=?INR"
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:openexchangeURl]];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
values =[responseString JSONValue];
This will get you live rates:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://rate-exchange.appspot.com/currency?from=USD&to=INR&q=1"]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
NSDictionary *parsedDict = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
CGFloat value = [parsedDict[#"rate"] floatValue];
NSLog(#"Value: %f", value);
}];
The JSON response from that api looks like this:
{
to: "INR",
rate: 54.8245614,
from: "USD",
v: 54.8245614
}
Your original request didn't have an NSURLConnection and the response was not valid JSON (did not have double-quoted values for each item in the hash).

AFJSONRequestOperation with JSON encoded as NSISOLatin1StringEncoding crashing

I want to use AFNetworking more specifically AFJSONRequestOperation in a project to allow for easy async calls. I quickly tried using the sample code from AFNetworking GitHub Page
NSURL *url = [NSURL URLWithString:#"https://alpha-api.app.net/stream/0/posts/stream/global"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"App.net Global Stream: %#", JSON);
}
failure:nil];
[operation start];
Which works fine, But when I use the URL for MetOffice Datapoint it crashes, I believe this might be because of the encoding type of the JSON feed being NSISOLatin1StringEncoding which causes a problem with NSJSONSerialization
The way I currently handle this is
NSString *string = [NSString stringWithContentsOfURL:kMetOfficeAllSites encoding:NSISOLatin1StringEncoding error:&error];
NSData *metOfficeData = [string dataUsingEncoding:NSUTF8StringEncoding];
id jsonObject = [NSJSONSerialization JSONObjectWithData:metOfficeData options:kNilOptions error:&error]
But how do I handle this situation with AFJSONRequestOperation?
Thanks in Advance

AFNetworking POST to REST webservice

Brief backstory, our previous developer used ASIHTTPRequest to make POST requests and retrieve data from our webservice. For reasons unknown this portion of our app stopped working. Seemed like good enough time to future proof and go with AFNetworking. REST webservice runs on the CakePHP framework.
In short I am not receiving the request response string using AFNetworking.
I know the webservice works because I am able to successfully post data and receive the proper response using curl:
curl -d "data[Model][field0]=field0value&data[Model][field1]=field1value" https://example.com/api/class/function.plist
Per the previous developer's instructions I came up with the following.
#import "AFHTTPRequestOperation.h"
…
- (IBAction)loginButtonPressed {
NSURL *url = [NSURL URLWithString:#"https://example.com/api/class/function.plist"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setValue:[usernameTextField text] forHTTPHeaderField:#"data[User][email]"];
[request setValue:[passwordTextField text] forHTTPHeaderField:#"data[User][password]"];
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"operation hasAcceptableStatusCode: %d", [operation.response statusCode]);
NSLog(#"response string: %# ", operation.responseString);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", operation.responseString);
}];
[operation start];
}
output:
operation hasAcceptableStatusCode: 200
response string: a blank plist file
attempted solution 1:
AFNetworking Post Request
the proposed solution uses a function of AFHTTPRequestOperation called operationWithRequest. However, when I attempt to use said solution I get a warning "Class method '+operationWithRequest:completion:' not found (return type defaults to 'id'"
attempted solution 2: NSURLConnection. output: I'm able to print the success log messaged but not the response string.
*update - returns blank plist.
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSString *httpBodyData = #"data[User][email]=username#example.com&data[User][password]=awesomepassword";
[httpBodyData dataUsingEncoding:NSUTF8StringEncoding];
[req setHTTPMethod:#"POST"];
[req setHTTPBody:[NSData dataWithContentsOfFile:httpBodyData]];
NSHTTPURLResponse __autoreleasing *response;
NSError __autoreleasing *error;
[NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
// *update - returns blank plist
NSData *responseData = [NSURLConnection sendSynchronousRequest:req returningResponse:nil error:nil];
NSString *str = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"responseData %#",str);
if (error == nil && response.statusCode == 200) {
// Process response
NSLog(#"success");//returns success code of 200 but blank
NSLog(#"resp %#", response );
} else {
// Process error
NSLog(#"error");
}
These are the essential (stripping out conditions I've made for my own use) lines that ended up satisfying my request to the web service. Thanks for the suggestions #8vius and #mattt !
- (IBAction)loginButtonPressed {
NSURL *baseURL = [NSURL URLWithString:#"https://www.example.com/api/class"];
//build normal NSMutableURLRequest objects
//make sure to setHTTPMethod to "POST".
//from https://github.com/AFNetworking/AFNetworking
AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:baseURL];
[httpClient defaultValueForHeader:#"Accept"];
NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
[usernameTextField text], kUsernameField,
[passwordTextField text], kPasswordField,
nil];
NSMutableURLRequest *request = [httpClient requestWithMethod:#"POST"
path:#"https://www.example.com/api/class/function" parameters:params];
//Add your request object to an AFHTTPRequestOperation
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc]
initWithRequest:request] autorelease];
//"Why don't I get JSON / XML / Property List in my HTTP client callbacks?"
//see: https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-FAQ
//mattt's suggestion http://stackoverflow.com/a/9931815/1004227 -
//-still didn't prevent me from receiving plist data
//[httpClient registerHTTPOperationClass:
// [AFPropertyListParameterEncoding class]];
[httpClient registerHTTPOperationClass:[AFHTTPRequestOperation class]];
[operation setCompletionBlockWithSuccess:
^(AFHTTPRequestOperation *operation,
id responseObject) {
NSString *response = [operation responseString];
NSLog(#"response: [%#]",response);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", [operation error]);
}];
//call start on your request operation
[operation start];
[httpClient release];
}
Use AFHTTPClient -postPath:parameters:success:failure:, passing your parameters (nested dictionaries/arrays are fine). If you're expecting a plist back, be sure to have the client register AFPropertyListRequestOperation.
In any case, setValue:forHTTPHeaderField: is not what you want here. HTTP headers are for specifying information about the request itself; data is part of the request body. AFHTTPClient automatically converts parameters into either a query string for GET requests or an HTTP body for POST, et al.

Empty JSON returned by AFNetworking on iOS5

I'm trying to load a simple JSON inside my iPhone app using the AFNetworking library. I'm using two different approaches:
NSURL *url = [NSURL URLWithString:#"http://www.mysite.com/test.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
NSLog(#"Name: %#", [JSON valueForKeyPath:#"name"]);
} failure:^(NSURLRequest* req,NSHTTPURLResponse *req2, NSError *error,id mex) {
NSLog(#"%#", [error description]);
}];
[operation start];
and using AFHttpClient (which would be my favorite,since it has all the features for dealing with my REST API:
NSString *baseurl = #"http://www.mysite.com";
NSString *path = #"/test.json";
AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:baseurl]];
[client registerHTTPOperationClass:[AFJSONRequestOperation class]];
//[client setAuthorizationHeaderWithUsername:#"myusername" password:#"mypassword"];
[client getPath:path parameters:nil success:^(AFHTTPRequestOperation *operation, id JSON) {
//NSLog(#"sjson: %#", [JSON valueForKeyPath:#"entries"]);
NSLog(#"sjson: %#", JSON);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error Code: %i - %#",[error code], [error localizedDescription]);
}];
now,the problem: in both cases I'm receiving an empty Json. I've tested the server side and the web-service is giving the right response and the right MIME type (application/json).
I've already checked this discussion https://github.com/AFNetworking/AFNetworking/issues/175
but my target is pointing to 5.0 and ARC is not enabled for the AFNetworking library.
Maybe I'm missing something obvious here,but I cannot fix it at the moment.
Thanks a lot!
Claus