Sending a message from Objective-C and getting the return value? - objective-c

I have this code
NSString *tr = [self sendUrl:#"http://google.com/"];
But for some reason 'tr' will remain nil after it is executed. What am I doing wrong?
sendUrl :
- (NSString *)sendUrl:(NSString *) uri {
NSLog(#"Requesting URI 1 ...");
// Prepare URL request to download statuses from Twitter
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:uri]];
NSLog(#"Requesting URI 2 ...");
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSLog(#"Requesting URI 3 ...");
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog(#"Requesting URI 4 ...");
return json_string;
}

Are you absolutely certain that response is not nil? If your request to Google or wherever fails, response will be set to nil and the error will contain some information that will help you diagnose the error so change
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
to
NSError* error = nil;
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (response == nil)
{
NSLog(#"request failed with error %#", error);
// any other error handling
}
Next thing. The default encoding for an HTTP message is ISO-8859-1, not UTF-8. According to Apple's docs, -initWithData: will return nil if the encoding is wrong. You probably want NSISOLatin1StringEncoding. I say "probably" because HTTP has a mechanism for telling you what character encoding it used. I think it's the header Content-Transfer-Encoding but I advise you to Google the HTTP RFC to find out for sure.
Finally if json_string were not nil, it would be leaking. Because you obtained it with alloc, you own it which means you need to autorelease it before returning it from sendURL: This last point is not the cause of your problem, it is a separate bug in your code.

Related

objective c parsing returned json from wcf service

So I asked this question recently and I was able to make it work
objective c calling wcf rest service request
Here's my code
NSString *urlStringRequest = [NSString stringWithFormat:#"http://service.mydomain.com/UserAccountService.svc/UserLogin?id=%#&pword=%#", email, incPassword];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStringRequest]];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
id jsonResult = [self parseJsonResult:result];
NSLog(#"Json Result Woop: %#", jsonResult);
the parseJsonResult is exactly the same as the one that was on the link. My problem is though, whenever I would show the jsonResult on the NSLog, it would show the json result which is:
Json Result Woop: {
Authenticated = 0;
Message = "Invalid Log In.";
}
But I'm not really sure how I can go into the variable and retrieve the key and it's value one by one.
I tried to do this:
NSError *jsonParseError = nil;
NSMutableArray *jsonArray = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:&jsonParseError];
if(!jsonArray)
NSLog(#"Parse error: %#", jsonParseError);
else
for(NSDictionary *item in jsonArray)
NSLog(#"%#", item);
using the result variable but it would just give me the keys.
Not really sure what to do.
JsonResult is already an NSDictionary as evidenced by NSLog showing it like this with curly braces. Just use
jsonResult[#"Message"]
to get to the value for the Message key.

NSURLConnection closes early on GET

I'm working on a method to centralize my URL connections for sending and receiving JSON data from a server. It works with POST, but not GET. I'm using a Google App Engine server and on my computer it'll handle the POST requests and return proper results (and log appropriately), but I get the following error when I try the request with a GET method:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0xd57e400 {NSErrorFailingURLKey=http://localhost:8080/api/login, NSErrorFailingURLStringKey=http://localhost:8080/api/login}
In addition, the GAE dev server shows a "broken pipe" error, indicating that the client closed the connection before the server was finished sending all data.
Here's the method:
/* Connects to a given URL and sends JSON data via HTTP request and returns the result of the request as a dict */
- (id) sendRequestToModule:(NSString*) module ofType:(NSString*) type function:(NSString*) func params:(NSDictionary*) params {
NSString *str_params = [NSDictionary dictionaryWithObjectsAndKeys:func, #"function", params, #"params", nil];
NSString *str_url = [NSString stringWithFormat:#"%#%#", lds_url, module];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:str_url]];
NSData *data = [[NSString stringWithFormat:#"action=%#", [str_params JSONString]] dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPMethod:type];
[request setHTTPBody:data];
[request setValue:[NSString stringWithFormat:#"%d", [data length]] forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSURLResponse *response = nil;
NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSLog(#"Error: %#", error);
NSLog(#"Result: %#", [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]);
return [result objectFromJSONData];
}
A sample call would be:
NSDictionary *response = [fetcher sendRequestToModule:#"login" ofType:#"GET" function:#"validate_email" params:dict];
Again, this works with a POST but not a GET. How can I fix this?
In my case i was not calling [request setHTTPMethod: #"POST" ]
I think the root cause is you have an invalid URL.
JSON encoding will include things like '{', '}', '[' and ']'. All of these need to be URL encoded before being added to a URL.
NSString *query = [NSString stringWithFormat:#"?action=%#", [str_params JSONString]];
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", str_url, query]];
To directly answer your question:
According to CFNetwork Error Codes Reference the error is kCFErrorHTTPParseFailure. This means the client failed to correctly parse the HTTP response.
The reason why is that a GET doesn't include a body. Why would you want to submit JSON in a GET anyways?
If the target api returns data only you pass it in the url params.
If you want to send data and "get" a response use a post and examine the body on return.
Sample Post:
NSError *error;
NSString *urlString = [[NSString alloc] initWithFormat:#"http://%#:%#/XXXX/MVC Controller Method/%#",self.ServerName, self.Port, sessionId ];
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding ]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
// hydrate the remote object
NSString *returnString = [rdc JSONRepresentation];
NSData *s10 = [returnString dataUsingEncoding:NSUTF8StringEncoding];
[request setHTTPBody:s10];
NSURLResponse *theResponse = [[NSURLResponse alloc] init];
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&theResponse error:&error];
NSString *message = [[NSString alloc] initWithFormat: #"nothing"];
if (error) {
message = [[NSString alloc] initWithFormat:#"Error: %#", error];
} else {
message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
NSLog(#"%#", message);
return message;

How to access secured url from ios

I'm trying to access a secure url from ios. Basically url will prompt the user with Username and Password. How can I send username and Password from ios?
My Code
Here is the Methods that I'm using to access JSON Parser
- (NSString *)stringWithUrl:(NSURL *)url{
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:30];
// Fetch the JSON response
NSData *urlData;
NSURLResponse *response;
NSError *error;
// Make synchronous request
urlData = [NSURLConnection sendSynchronousRequest:urlRequest
returningResponse:&response
error:&error];
// Construct a String around the Data from the response
return [[[NSString alloc] initWithData:urlData encoding:NSUTF8StringEncoding] autorelease];}
- (id) objectWithUrl:(NSURL *)url{
SBJsonParser *jsonParser = [[[SBJsonParser alloc]init] autorelease];
NSString *jsonString = [self stringWithUrl:url];
// Parse the JSON into an Object
return [jsonParser objectWithString:jsonString error:nil]; }
Here is the piece of code that I'm retrieving json keys to my dictionary.
- (NSDictionary *) downloadFeed {
id response = [self objectWithUrl:[NSURL URLWithString:#"http://mysite.com/Services/Secure.svc/GetList?id=2127"]];
NSDictionary *feed = (NSDictionary *)response;
return feed; }
Can someone let me know where can I pass the Username and Password to this url?
Either switch to ASIHTTPRequest, which handles Basic authentication simply, or use a NSMutableRequest and set the Authorization header correctly, with a base64 encoded user:password pair.

Creating a POST/GET request using Objective -C [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Tutorials for using HTTP POST and GET on the iPhone in Objective-C
Is there away to create an NSArray with the correct information like id = 1, name = #"John", score = 100 then send it and receive a response from the server?
Maybe display it inside an NSLog();
Can anyone help answer this question by linking me to a good tutorial, I don't want to use ASIHTTPRequest either. I know it would be much simpler but if there is away to do something without using a load of prewritten code id rather learn how to make something using the functionality the the foundation framework offers before going off using someone elses classes.
What you're looking for is NSMutableURLRequest and the addValue:forHTTPHeaderField method.
Create the request with the URL you wish to communicate with. Load the values you wish to transmit into the header or into the HTTPBody, set your HTTPMethod and then use a NSURLConnection method to send and receive the response.
As for an array with the information you could simply enumerate through the array and add the values to the HTTPHeaderFields. It really depends on what the server is setup to receive.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html#//apple_ref/doc/uid/10000165i
Has more information.
NSString *urlString = #"http://yoururl.com";
NSURL *url = [NSUL URLWithString:urlString];
NSMutalbeURLRequest *request = [NSMutableURLRequest requestWithURL:url];
NSDictionary *headerInformation = [NSDictionary dictionaryWithObjectsAndKeys:#"1",#"id",#"John",#"name",#"100",#"score", nil];
for (NSString *key in [headerInformation allKeys])
{
[request addValue:[dict valueForKey:key] forHTTPHeaderField:key];
}
NSHTTPURLResponse *response = nil;
NSError *error = nil;
// this will perform a synchronous GET operation passing the values you specified in the header (typically you want asynchrounous, but for simplicity of answering the question it works)
NSData *responseData = [NSURLConnection sendSynchronousRequest:request reuturningResponse:&response error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"Response: %#", responseString);
[responseString release];
It might be easier to just use NSData to send a url request and store the response then to reinvent the wheel. Here is some code similar to something in my production project:
+ (NSData *)getProfiles {
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:#"token"];
// Create string of the URL
NSString *serviceURL = [NSString stringWithFormat:#"http://www.myurlhere.com/getProfiles.php?token=%#", token];
NSLog(#"Service URL : %#", serviceURL);
// Create a NSURL out of the string created earlier. Use NSASCIIStringEncoding to make it properly URL encoded (replaces " " with "+", etc)
NSURL *URL = [NSURL URLWithString:[serviceURL stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding]];
// Request the url and store the response into NSData
NSData *data = [NSData dataWithContentsOfURL:URL];
if (!data) {
return nil;
}
// Since I know the response will be 100% strings, convert the NSData to NSString
NSString *response = [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
// Test response and return a string that an XML Parser can parse
if (![response isEqualToString:#"UNAUTHORIZED"]) {
response = [response stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
data = [response dataUsingEncoding:NSASCIIStringEncoding];
return data;
} else {
return nil;
}
}
NSLog output:
[Line: 476] +[WebSupport getProfiles]: Service URL : http://www.myurlhere.com/getProfiles.php?token=abcdef0123456789abcdef0123456789

Objective C: Function returning correct data for the first time of call and null for other times

Am a beginner in objective C, i am implementing a function that would query a web server and display the returning string in console. I am calling the function (getDatafromServer) repeatedly in a loop. The problem is that the first time am getting the value whereas the other times, it returns me a (null) in console... I've searched about memory management and check out on the forums but none have worked. Can you please guys tell me where am wrong in the codes below? Thanks in advance....
#implementation RequestThread
+(void)startthread:(id)param{
while (true) {
//NSLog(#"Test threads");
sleep(5);
NSLog(#"%#",[self getDatafromServer]);
}
}
+(NSString *) getDatafromServer{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *myRequestString = #"name=Hello%20&email=essssss#live.com";
NSData *myRequestData = [NSData dataWithBytes:[myRequestString UTF8String] length:[myRequestString length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:#"http://192.168.1.32/gs/includes/widget/getcalls.php?user=asdasd&passw=asdasdasd"]];
[request setHTTPMethod:#"POST"];
[request setHTTPBody: myRequestData];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *myString = [NSString stringWithUTF8String:[returnData bytes]];
[myRequestString release];
[request release];
[returnData release];
return myString;
[pool release];
}
#end
You have a problem with the autorelease pool. Firstly, as Nickolay has said, the release never happens because it is after the return. I'm amazed you aren't seeing compiler warnings. Make sure you have -Wall set in "other warning flags" and you have the "Run static analyzer" build option set.
Since you want to use the returned string outside of the function, the autorelease pool must also be outside the function, or the string may be deallocated before your log gets to it. Your code structure should look more like:
+(void)startthread:(id)param
{
while (true)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
//NSLog(#"Test threads");
sleep(5);
NSLog(#"%#",[self getDatafromServer]);
[pool drain]; // use instead of release in case you move to GC
}
}
The other problem you have is that you are not doing any error checking. How can you be sure that:
the request to the server is working?
the response from the server is encoded as UTF-8.
You need to check if returnData is nil after you get it and you need to examine the NSError if it is. So you need something like this:
NSError* error = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
if (returnData == nil)
{
the error object will be set and contain useful info.
}
You also need to check if myString is nil. If it is, it will be because the response was not encoded as UTF-8. With HTTP the default encoding is not UTF-8, it is ISO-8859-1. Also, the body of the response might not be character data at all. You need to examine the response to find out how to decode the data. So the code snippet I posted above should really look like:
NSError* error = nil;
NSURLResponse* response = nil;
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (returnData == nil)
{
// the error object will be set and contain useful info.
}
else
{
// You can get the content type and encoding from the response here.
}
Edit
Also, your code violates the Memory Management Rules. You did not obtain myRequestString or returnData through alloc, copy or new, neither have you retained them, so you must not release them.
That's bad idea to use autorelease pool in this function, and release it after 'return'.
Remove pool and everything should be ok.