Is there a way using the iPhone SDK to get the same results as an HTTP POST or GET methods?
Assume your class has a responseData instance variable, then:
responseData = [[NSMutableData data] retain];
NSURLRequest *request =
[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.domain.com/path"]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
And then add the following methods to your class:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// Show error
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Once this method is invoked, "responseData" contains the complete result
}
This will send a GET. By the time the final method is called, responseData will contain the entire HTTP response (convert to string with [[NSString alloc] initWithData:encoding:].
Alternately, for POST, replace the first block of code with:
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:#"http://www.domain.com/path"]];
[request setHTTPMethod:#"POST"];
NSString *postString = #"Some post string";
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
If you're using Objective C, you'll need to use the NSURL, NSURLRequest, and NURLConnection classes. Apple's NSURLRequest doc. HttpRequest is for JavaScript.
Related
I have trouble finding info on this topic. Please help me out here.
I need to pass arguments via POST or GET method to my web server and get a reply.
Basically, if using GET method, I want to do something like server.com/?user=john&password=smith and receive the dynamically generated HTML code that is done with my php script. All this without using the web browser on my app.
How is it usually done?
You'll want to look into NSMutableURLRequest and NSURLConnection.
For example, you could use them like this do to a GET request to your server:
- (void)loginUser:(NSString *)username withPassword:(NSString *)password {
// GET
NSString *serverURL = [NSString stringWithFormat:#"http://yourserver.com/login.php?user=%#&pass=%#", username, password];
NSURL *url = [NSURL URLWithString:serverURL];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:req delegate:self];
if (connection) {
connectionData = [[NSMutableData alloc] init];
}
}
This will send an asynchronous GET request to your server with the query string containing username and password.
If you want to send username and password using a POST request, the method would look something like this:
- (void)loginUser:(NSString *)username withPassword:(NSString *)password {
// POST
NSString *myRequestString = [NSString stringWithFormat:#"user=%#&pass=%#",username,password];
NSData *myRequestData = [NSData dataWithBytes: [myRequestString UTF8String] length: [myRequestString length]];
NSURL *url = [NSURL URLWithString:#"http://yourserver.com/login.php"];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
[req setHTTPMethod: #"POST"];
[req setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"content-type"];
[req setHTTPBody: myRequestData];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:req delegate:self];
if (connection) {
connectionData = [[NSMutableData alloc] init];
}
}
In order to get the response from the server, you will need to implement the NSURLConnection delegate methods, for example:
#pragma mark -
#pragma mark NSURLConnection delegate methods
#pragma mark -
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// Called if you have an .htaccess auth. on server
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:#"your_username" password:#"your_password" persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[connectionData setLength: 0];
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[connectionData appendData:data];
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connectionData release];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *content = [[NSString alloc] initWithBytes:[connectionData bytes]
length:[connectionData length] encoding: NSUTF8StringEncoding];
// This will be your server's HTML response
NSLog(#"response: %#",content);
[content release];
[connectionData release];
}
References:
NSMutableURLRequest Class Reference
NSURLConnection Class Reference
Hope this helps :)
Usually this is done using a NSURLConnection. You can also use NSString's method stringWithContentsOfURL.
I would like to know how do I get a return value 1 or 0 only.... back from an URL request asynchronously.
currently I do it in this way:
NSString *UTCString = [NSString stringWithFormat:#"http://web.blah.net/question/CheckQuestions?utc=%0.f",[lastUTCDate timeIntervalSince1970]];
NSLog(#"UTC String %#",UTCString);
NSURL *updateDataURL = [NSURL URLWithString:UTCString];
NSString *checkValue = [NSString stringWithContentsOfURL:updateDataURL encoding:NSASCIIStringEncoding error:Nil];
NSLog(#"check Value %#",checkValue);
this works, however it is blocking my main thread till I got a reply back from the URL, how do I set it so it will do it in a another thread instead of the main thread ?
EDIT: ANSWER
I end upcalling my function with this, it works well :)
[self performSelectorInBackground:#selector(shouldCheckForUpdate) withObject:nil];
you can use NSURLConnection class
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
and handle its response and errors using its delegate methods.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
You can find implementation of NSURLConnection
Apple docs: Using NSURLConnection
How To Use iOS NSURLConnection By Example
Edit: Although NSURLConnection is provided by apple is more recommended way of placing URL request. But I found AFNetworking library very time saving, easy to implement and robust yet simple as third party implementation. You should give it a try.
try this :
.h:
NSMutableData *responseData;
.m:
- (void)load
{
NSURL *myURL = [NSURL URLWithString:#"http://www.example.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[responseData release];
[connection release];
[textView setString:#"Unable to fetch data"];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[responseData
length]);
NSString *txt = [[[NSString alloc] initWithData:responseData encoding: NSASCIIStringEncoding] autorelease];
}
Use NSURLConnection and make your request.
Then you may start synchronous or asynchronous connection with NSURLConnection's methods :
Loading Data Synchronously
+ sendSynchronousRequest:returningResponse:error:
Loading Data Asynchronously
+ connectionWithRequest:delegate:
– initWithRequest:delegate:
– initWithRequest:delegate:startImmediately:
– start
Check the NSURLConnection class in Apple Developer API Reference.
Shamelessly copy from https://gist.github.com/knmshk/3027474. All credits go to https://gist.github.com/knmshk.
xmlData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:
#"http://forrums.bignerdranch.com/smartfeed.php?"
#"limit=NO_LIMIT&count_limit20&sort_by=standard&"
#"feed_type=RSS2.0&feed_style=COMPACT"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[NSURLConnection sendAsynchronousRequest:request
queue:queue
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (error) {
xmlData = nil;
NSLog(#"error:%#", error.localizedDescription);
}
[xmlData appendData:data];
}];
There is an example in the iOS XCode documentation called LazyTableImages. This does an asynchronous URL as well as asynchronous image load into UITableView cells displayed on the screen after scrolling stops. Excellent example of protocols, asynchronous data handling, etc.
I have a problem now. I need to pass an transactionID and an user password to a rest service and it is suppose to return me a true/false value (in XML format). However, it is consistently returning me (null).. I am totally lost some one please help.
NSString *urlString = [NSString stringWithFormat:#"https://10.124.128.93:8443/axis2/services/C3WebService/completeWithdrawal Transaction?transactionId=%#&password=%#", _transactionID.text, _userPassword.text];
NSURL *url = [[NSURL alloc] initWithString:urlString];
NSString *result = [[NSString alloc] initWithContentsOfURL:url];
NSLog(#"%#",result );
My result is constantly returning me null. How do i continue from here?
.h:
NSMutableData *responseData;
.m:
- (void)load {
NSURL *myURL = [NSURL URLWithString:#"https://10.124.128.93:8443/axis2/services/C3WebService/completeWithdrawal Transaction?transactionId=%#&password=%#", _transactionID.text, _userPassword.text];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:myURL
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[responseData release];
[connection release];
[textView setString:#"Unable to fetch data"];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[responseData
`enter code here` length]);
NSString *txt = [[[NSString alloc] initWithData:responseData encoding: NSASCIIStringEncoding] autorelease];
}
Consider using NSURLConnection which has a callback for the result and also a callback to get detailed error details. It als doesn't execute on the UI thread (doesn't hang UI during the request).
NSURL *url = [NSURL URLWithString:#"http://www.mysite.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setHTTPMethod:#"GET"];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Then you can implement the delegate methods to get the error, the data and other details:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
NSString* responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"result: %#", responseString);
[responseString release];
}
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"error - read error object for details");
}
You might try using "initWithContentsOfURL:encoding:error:" instead and check "error". Also, use Charles or other http sniffer and compare results to a straight browser request ( did you check results in a browser?)
I have a NSURLConnection which I am calling every time -(void)viewWillAppear:animated is called (that's only for now, it's just for testing)
I am doing it like this
receivedData = [[NSMutableData data] retain];
NSString *urlString = #"<URL hidden>";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30.0];
[NSURLConnection connectionWithRequest:request delegate:self];
Then I have these three delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *returnString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
usersPhotos = [[NSMutableArray alloc] initWithArray:[[returnString JSONValue] objectForKey:#"data"]];
[self loadAnnotations];
NSLog(#"%#", returnString);
[returnString release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self loadAnnotations];
}
Even though I am sure the returnStringshould change (I can visit the site in urlString and confirm it has changed) it is always the same.
It is as if it reuses the data that it retrieves from the first connection.
Does anyone know why this is?
it should be your cache policy, i will update in a second with the correct info.
UPDATE
Try setting your cahce policy to: cachePolicy:NSURLRequestReloadIgnoringCacheData
It should be:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30.0];
You need to empty your buffer if you're re-using it.
Add this method:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
Can anyone tell me the way how I can make a synchronous call to the https server? I am able to do asynchronous request on https server using following delegate methods.
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace
and
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
but I need to do synchronous.
//Encoding the request
NSData *postData = [xmlText dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
**//Calculating length of request**
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:requestUrlString]];
[request setHTTPMethod:#"POST"];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/xml" forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:postData];
NSURLResponse* response;
NSError* error = nil;
//Capturing server response
NSData* result = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error
in NSUrlConnection should work just fine with https.
If you'd like to provide credentials, they need to be part of the url: (https://username:password#domain.tld/api/user.json).
There's no way to provide a NSURLConnection delegate, so if you need some nonstandard authentication handling you'll need to do it asynchronously.
That's how i did it:
instead of
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]
I made the same method instance based, on the containing class, since we will need a delegate. And don't make it singleton, so every connection has its independent variables, because, if we don't, and two connections happen to be called before the other finishes, then the received data and the handling of the loops will be intertwined irrecoverably.
[[ClassNameHere new] sendSynchronousRequest:request returningResponse:&response error:&error]
This way i can create an NSUrl connection and handle it (in a synchronous way, we'll see how) so i don't have to change any of the previously written code.
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse *__strong*)response error:(NSError *__strong*)error
{
_finishedLoading=NO;
_receivedData=[NSMutableData new];
_error=error;
_response=response;
NSURLConnection*con=[NSURLConnection connectionWithRequest:request delegate:self];
[con start];
CFRunLoopRun();
return _receivedData;
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
//handle the challenge
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
*_response=response;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
*_error=error;
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
CFRunLoopStop(CFRunLoopGetCurrent());
}
The trick was in the CFRunLoopRun() and CFRunLoopStop(CFRunLoopGetCurrent())
I hope it helps someone else in the futur.