Handling a String From a Web API Service in Object-C - objective-c

I have a simple Web API Service POST
// POST api/values
public string Post(SimpleRequest request)
{
if (request == null || string.IsNullOrEmpty(request.Field1) || string.IsNullOrEmpty(request.Password))
return "Something is missing.";
return string.Format("Success. You sent {0}!", request.Field1);
}
Which is consumed in an a object-c method (for an iphone project):
- (IBAction)doSomethingButtonWasPressed:(id)sender {
NSString * urlString = #"http://192.168.0.XXX/api/Test";
NSDictionary *postDict = [[NSDictionary alloc] initWithObjectsAndKeys:
_field1.text, #"Field1",
_field2.text, #"Field2",
nil];
NSURL *url=[NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *req= [NSJSONSerialization dataWithJSONObject:postDict options:NSJSONWritingPrettyPrinted error:nil];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];//
[request setHTTPBody:req];
NSURLResponse* response;
NSError* error = nil;
NSData* responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"The output is:%#",responseString);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: #"Result"
message:responseString
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
It all works, except the result has "quotes" around it. I feel like maybe I'm missing a decoding step?

It's possible the service is returning JSON, like {"foo"} that would appear as a quoted string. Try interpreting the data as JSON with ...
NSError *error;
id result = [NSJSONSerialization JSONObjectWithData:responseData options:nil error:&error];
NSLog(#"result is %#, error is %#", result, error);

Related

Recreate JSON data in Objective-C

I'm trying to build an app on the Feedly API. In order to be able to mark categories as read, I need to post some data to the API. I'm having no success, though.
This is what the API needs as input:
{
"lastReadEntryId": "TSxGHgRh4oAiHxRU9TgPrpYvYVBPjipkmUVSHGYCTY0=_1449255d60a:22c3491:9c6d71ab",
"action": "markAsRead",
"categoryIds": [
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/photography"
],
"type": "categories"
}
And this is my method:
- (void)markCategoryAsRead: (NSString*)feedID{
NSLog(#"Feed ID is: %#", feedID);
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *accessToken = [standardUserDefaults objectForKey:#"AccessToken"];
NSString *feedUrl = [NSURL URLWithString:#"https://sandbox.feedly.com/v3/markers"];
NSError *error = nil;
NSDictionary *tmp = [[NSDictionary alloc] initWithObjectsAndKeys:
#"markAsRead", #"action",
#"categories", #"type",
#[feedID], #"categoryIds",
#"1367539068016", #"asOf",
nil];
NSData *postdata = [NSJSONSerialization dataWithJSONObject:tmp options:0 error:&error];
NSLog(#"Postdata is: %#", postdata);
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:feedUrl];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-type"];
[request addValue:accessToken forHTTPHeaderField:#"Authorization"];
//[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *errror = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&errror];
NSLog(#"Response code: %ld", (long)[response statusCode]);
if ([response statusCode] >= 200 && [response statusCode] < 300)
{
NSLog(#"It's marked as read.");
} else {
if (error) NSLog(#"Error: %#", errror);
NSLog(#"No success marking this as read. %#", response);
}
}
It keeps throwing a 400 error though, saying bad input. What am I doing wrong?
You're not doing anything with postdata after creating it. Attach it to the request.
[request setHTTPBody:postData];
There are a few problems in your code. Here are some I noticed:
You're not using postData.
The dictionary you make in tmp doesn't look like the dictionary you said you wanted to send. Where's lastReadEntryId, for example?
NSString *feedUrl should be NSURL *feedUrl
Stylistically, you should be using the dictionary literal syntax to create your dictionary. This will make it easier to debug.

NSJSONSerialization returns EXC_BAD_ACCESS

I am parsing a JSON file created by a PHP-Script using NSJSONSerialization.
When I clear the code (Product - clear) it works perfectly. But when I stop the program and build it again without Product - clear, it will crash at this line with EXC_BAD_ACCESS.
I use ARC.
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:adresse]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSError *jsonParsingError = nil;
if (response == nil) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Connection" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}
else {
if (![NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError]) {
UIAlertView *jsonAlert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"JSON Parsingerror" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[jsonAlert show];
}
else {
jsonData = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
Working around the problem caused by escaped unicode characters by adding this
NSString *escaped = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSString *name = [NSString
stringWithCString:[escaped cStringUsingEncoding:NSUTF8StringEncoding]
encoding:NSNonLossyASCIIStringEncoding];
NSData *responseData = [name dataUsingEncoding:NSUTF8StringEncoding];
responseData = [responseData subdataWithRange:NSMakeRange(0, [responseData length]-1)];
and changing
jsonData = [NSJSONSerialization JSONObjectWithData:response options:0 error:&jsonParsingError];
to
jsonData = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonParsingError];
results in a SIGABRT crash.
What am I doing wrong? It WORKS for the first time AFTER product clear but then crashes with EXC_BAD_ACCESS despite using ARC.
My JSON looks like that
[{"line":"ABC","date":"2013-10-02","description":"H\u00e4hnchenbrust mit Calvadosso\u00dfe (1,2,4,8)","art":"type1"},{"line":"DEF","date":"2013-10-02","description":"Frika‌​dellen \u0084Polpette\u0093 (Rind) mit Sardellen und Tomaten (8)","art":"type1"},{"line":"ABC","date":"2013-10-03","description":"Salatteller mit Gem\u00fcseschnitzel (4,2,8)","art":"type2"},{"line":"ABC","date":"2013-10-27","description":"Nudel-H‌​ackfleisch-Pfanne (Rind) mit Schafsk\u00e4se (2,4)","art":"type1"}]
If you want to replace those escape sequences, you can use CFStringTransform:
NSMutableString *escaped = [[NSMutableString alloc] initWithData:response encoding:NSUTF8StringEncoding];
CFStringTransform((__bridge CFMutableStringRef)escaped, NULL, CFSTR("Any-Hex/Java"), YES);
NSData *unescapedData = [escaped dataUsingEncoding:NSUTF8StringEncoding];
I guess I solved the problem. I used a separate class JSONParser.h /.m which was build again and again. I now just parse using the code directly from the parental class and it is working.

Trying to login to a website in iOS app, no JSON response

I'm trying to login to a website and get a response using JSON using this code:
#try {
if([[txtUsername text] isEqualToString:#""] || [[txtPassword text] isEqualToString:#""] ) {
[self alertStatus:#"Please enter both Username and Password" :#"Login Failed!"];
} else {
NSString *post =[[NSString alloc] initWithFormat:#"username=%#&password=%#",[txtUsername text],[txtPassword text]];
NSLog(#"PostData: %#",post);
NSURL *url=[NSURL URLWithString:#"https://yedion.afeka.ac.il/yedion/fireflyweb.aspx?prgname=login"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];
NSError *error = [[NSError alloc] init];
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Response code: %d", [response statusCode]);
if ([response statusCode] >=200 && [response statusCode] <300)
{
NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
NSLog(#"Response ==> %#", responseData);
SBJsonParser *jsonParser = [SBJsonParser new];
NSDictionary *jsonData = (NSDictionary *) [jsonParser objectWithString:responseData error:nil];
NSLog(#"%#",jsonData);
NSInteger success = [(NSNumber *) [jsonData objectForKey:#"success"] integerValue];
NSLog(#"%d",success);
if(success == 1)
{
NSLog(#"Login SUCCESS");
[self alertStatus:#"Logged in Successfully." :#"Login Success!"];
} else {
NSString *error_msg = (NSString *) [jsonData objectForKey:#"error_message"];
[self alertStatus:error_msg :#"Login Failed!"];
}
} else {
if (error) NSLog(#"Error: %#", error);
[self alertStatus:#"Connection Failed" :#"Login Failed!"];
}
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
[self alertStatus:#"Login Failed." :#"Login Failed!"];
}
In the log I can see there is no JSON response so I can't know if the login was successful or not.
Is there any other way to login to this website and get a response wether or not it was successful?
Thanks!
The code seems ok to me but do check the web service and also check that you give correct keywords for json if the key given to the objectForKey and your key in web service are different you will never get a json response.
Use Get method and try
[ request setHTTPMethod:#"GET" ];

JSON to Objective-C Dictionary

I'm making URL Request to an API but I dont know how to render the JSON, It generates an array of multiple users like this [{"user": "value"}, {"user":"value"}] and I was trying to use a TableView so I need an NSDictionary but i think is better to render a JSON like {users: [{"user": "value"}, {"user":"value"}]}. I have this code to make the request
#import "JSONKit.h"
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
users = [[jsonData objectFromJSONData] objectForKey:#"users"];
usersKeys = [users allKeys];
but I'm getting this error
2012-09-16 18:51:11.360 tableview[2979:c07] -[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180
2012-09-16 18:51:11.362 tableview[2979:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[JKArray allKeys]: unrecognized selector sent to instance 0x6d30180'
I dont really know how to accomplish this so any help is useful, thanks
You are getting that error because whatever got parsed out of "jsonData" isn't necessarily what you expected (i.e. a dictionary).
Perhaps you need some error checking in that code of yours.
For example:
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(jsonData)
{
id objectReturnedFromJSON = [jsonData objectFromJSONData];
if(objectReturnedFromJSON)
{
if([objectReturnedFromJSON isKindOfClass:[NSDictonary class]])
{
NSDictionary * dictionaryFromJSON = (NSDictionary *)objectReturnedFromJSON;
// assuming you declared "users" & "usersKeys" in your interface,
// or somewhere else in this method
users = [dictionaryFromJSON objectForKey:#"users"];
if(users)
{
usersKeys = [users allKeys];
} else {
NSLog( #"no users in the json data");
}
} else {
NSLog( #"no dictionary from the data returned by the server... check the data to see if it's valid JSON");
}
} else {
NSLog( #"nothing valid returned from the server...");
}
} else {
NSLog( #"no data back from the server");
}
I was thinking on something like this
NSError *error = nil;
NSURLResponse *response = nil;
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://localhost:3000/getusers"]];
[request setHTTPMethod:#"GET"];
NSData *jsonData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
JSONDecoder *decoder = [[JSONDecoder alloc]
initWithParseOptions:JKParseOptionNone];
NSArray *json = [decoder objectWithData:jsonData];
NSMutableArray *objects = [[NSMutableArray alloc] init];
NSMutableArray *keys = [[NSMutableArray alloc] init];
for (NSDictionary *user in json) {
[objects addObject:[user objectForKey:#"user" ]];
[keys addObject:[user objectForKey:#"value" ]];
}
users = [[NSDictionary alloc] initWithObjects:objects forKeys:keys];
NSLog(#"users: %#", users);
usersKeys = [users allKeys];
But it doesnt look efficient for many items or im wrong?

Geocoding API using JSonKit

I have trouble in parsing Google Geocoding API response. Here is the method :
-(void) findLatLong:(NSString*) adr{
NSString *encodedAddress = (NSString *) CFURLCreateStringByAddingPercentEscapes(
NULL, (CFStringRef) adr,
NULL, (CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
NSString* searchURL = [NSString stringWithFormat:#"http://maps.googleapis.com/maps/api/geocode/json?address=%#&sensor=true",encodedAddress];
NSError* error = nil;
NSURLResponse* response = nil;
NSMutableURLRequest* request = [[[NSMutableURLRequest alloc] init] autorelease];
NSURL* URL = [NSURL URLWithString:searchURL];
[request setURL:URL];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
[request setTimeoutInterval:30];
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error){
NSLog(#"Error performing request %#", searchURL);
return;
}
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString objectFromJSONString];
// to be added
}
I can get response json string from Geococing API. When I parse it with JSonKit I have two keys. These are result and status. But when I go one step further as below:
[[results objectForKey:#"results"] objectForKey:#"address_components"]
I always get null set. Any suggestion?
I am using XCode 4.2.1