I'm trying to make a basic app that takes in a persons details and posts it on a private server. My URL is kept blank for now, If I use the NSURLConnectionDelegate and use didFailWithError, it works saying there's no connection but when I try the NSLog method it says
"connection is made"
for some reason. This is my code
- (void) saveData{
NSString *name = self.NameTextField.text;
NSString *phoneNumber = self.phoneNumberTextField.text;
NSString *age = self.ageTextField.text;
NSString *email = self.emailTextField.text;
//Define the URL
NSURL *url = [[NSURL alloc]initWithString:#""];
//Initialize a request from the URL
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]];
//Specify that it will be a post request.
request.HTTPMethod = #"POST";
// This is how we set header fields
[request setValue:#"application/json; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSString *DataString = [NSString stringWithFormat:#"name=%#&phonenumber=%#&age=%#&email=%#",name,phoneNumber,age,email];
//Change your requests HTTPBody property
NSData *requestBodyData = [DataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestBodyData;
// Create url connection and fire request
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.connection = conn;
if(self.connection){
NSLog(#"Connection is made");
}else{
NSLog(#"Connection is not made");
}
[self.connection start];
}
Do inform if theres any other mistake in my code.
All that if (self.connection) is doing is checking to see if it's nil it's not actually checking to see if a connection has been made you do that at [self.connection start];. So essentially:
if (self.connection) {
NSLog(#"Connection is made");
} else {
NSLog(#"Connection is not made");
}
is the exact same as
if (self.connection != nil) {
NSLog(#"Connection is made");
} else {
NSLog(#"Connection is not made");
}
And self.connection is not nil because you assign conn to it which has been initialized. This can be seen in the two lines below from your code.
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.connection = conn;
What you could do if you are wanting to check whether the connection was successful or not is check the HTTP Status code in didReceiveResponse: (Code obtained from Checking for valid IP for connection with NSURLConnection)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
switch ([(NSHTTPURLResponse *)response statusCode]) {
case 200: {
NSLog(#"Received connection response!");
break;
}
default: {
NSLog(#"Something bad happened!");
break;
}
}
}
OR if it's just to see whether you can or not you could implement the Reachability code that Apple supplies or use another open source version.
Your code checks whether the self.connection variable is not null, which it's not since the alloc init seems to have executed successfully. i.e the object is created and that is what you are checking, whether it does what you want is a different story.
Related
I am new to iOS development. I was just trying to do a post request to a server, but encountered problems mentioned here with server redirection. I used the event handler mentioned in the answer, but things still do not work right.
Here is my .m code:
#interface ViewController ()
#end
#implementation ViewController
#pragma mark NSURLConnection Delegate Methods
//CALL BACK METHODS
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#" didReceiveResponse");
// A response has been received, this is where we initialize the instance var you created
// so that we can append data to it in the didReceiveData method
// Furthermore, this method is called each time there is a redirect so reinitializing it
// also serves to clear it
//initialize response
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#" didReceiveData");
// Append the new data to the instance variable you declared
[_responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
// Return nil to indicate not necessary to store a cached response for this connection
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#" connectionDidFinishLoading ");
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
NSString *dataReceived= [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
NSLog(#" async response data: %#", dataReceived);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#" didFailWithError");
// The request has failed for some reason!
// Check the error var
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSString *post = [NSString stringWithFormat:#"&j_username=%#&j_password=%#",#"usrname",#"pw"];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:#"%d", [postData length]];
request = [[NSMutableURLRequest alloc] init];
request.HTTPMethod= #"POST";
//parameters
[request setURL:[NSURL URLWithString:#"url"]];
[request setValue:postLength forHTTPHeaderField:#"Content-Length"];
[request setValue:#"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:#"Content-Type"];
[request setValue:#"XMLHttpRequest" forHTTPHeaderField:#"X-Requested-With"];
[request setHTTPBody:postData];
// Send a synchronous request
if (0) {
NSURLResponse * response = nil;
NSError * error = nil;
NSData * data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
NSLog(#" Synchronous request done");
if (error == nil)
{
// Parse data here
NSLog(#" Synchronous response has no error");
NSLog(#" Synchronous Reply: %#", response);
}
}
else {
// Send Asynchronous request
//NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[NSURLConnection connectionWithRequest:request delegate:self];
NSLog(#" Asynchronous request sent");
}
}
- (NSURLRequest *)connection: (NSURLConnection *)connection
willSendRequest: (NSURLRequest *)inRequest
redirectResponse: (NSURLResponse *)redirectResponse;
{
if (redirectResponse) {
// we don't use the new request built for us, except for the URL
NSURL *newURL = [request URL];
NSString *redirectURL= [newURL absoluteString];
NSLog(#"Redirect URL: ");
NSLog(redirectURL);
// Previously, store the original request in _originalRequest.
// We rely on that here!
NSMutableURLRequest *newRequest = [request mutableCopy];
[newRequest setURL: newURL];
NSLog(#"redirect occur");
return newRequest;
} else {
NSLog(#"no redirect");
return inRequest;
}
}
#end
Without the handler, the request goes through fine(just without the body attached); but with the handler, the redirection gets detected again and again b/c the redirected url is same as the original. Eventually the requested died because of too many redirects. I think this might be a server end problem, but am I doing anything wrong in the coding that causes this?
Basically the problem was that the url of the redirectResponse wasn't where you were redirected to; it's still the same one you set in the original post method. That was why you were being redirected to the same url again and again.
So what you wanna do is intercepting the actual url you are being redirected to in the response headers. After your initial post request was executed, you should get response headers like this:
HTTP/1.1 302 Found
Location: http://www.iana.org/domains/example/
where "Location" indicates where you are being redirected to. So get the url like so:
NSDictionary* headers = [(NSHTTPURLResponse *)redirectResponse allHeaderFields];
NSString newUrl=headers[#"Location"];
Use newUrl in your newRequest, then you should be good to go.
I have a little problem with my app. I want to send some http request asynchronously to server. I create this method:
- (void)sendHTTPRequest:(NSString *)urlString type:(NSString *)type idNegozio:(NSNumber *)idNegozio {
self.negozi = [[NSMutableArray alloc] init];
NSData *jsonData;
NSString *jsonString;
if ([type isEqualToString:#"shops"]) {
self.reqNeg = YES;
self.reqApp = NO;
...
jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:nil];
jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
else if ([type isEqualToString:#"appointments"])
{
[self.loadingIconApp startAnimating];
self.reqNeg = NO;
self.reqApp = YES;
...
jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:nil];
jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
NSString *requestString = [NSString stringWithFormat:urlString];
NSURL *url = [NSURL URLWithString:requestString];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:30];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody: jsonData];
NSURLConnection * conn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
[conn start];
}
and I use this methods for connection:
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
self.responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.responseData appendData:data];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse*)cachedResponse {
return nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (self.reqNeg == YES) {
//here use the responseData for my first http request
}
if (self.reqApp == YES) {
//here use the responseData for second http request
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
}
but in this way only the first connection works and I can use the responseData. While, If I try to send other http request the method connectionDidFinishLoading doesn't work and other methods too.
Anyone have an idea??
If you want to use the async request one by one you can do that:
- (void)request1 {
NSString *requestString = #"your url here";
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:[[NSURLRequest alloc]initWithURL:[NSURL URLWithString: requestString]]
queue:queue
completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error) {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (!error && httpResponse.statusCode >= 200 && httpResponse.statusCode <300) {
// call the request2 here which is similar to request 1
// your request2 method here
}
}];
}
hope this help you~ thank you~
Your code looks good to me. Here are my ideas:
Are you sure your second NSURLConnection is being created and sent out?
Maybe it's never being sent.
Are you calling your sendHTTPRequest:type:idNegozio: method with a different type while your second connection is still sent out?
You don't have a check at the beginning of the send function to make sure you're not already sending out a connection. Maybe your flags are being switched mid-connection.
The if statements in your didFinish method should probably be combined with an else. Just in case you wanted to fire off an 'app' connection after handling a 'neg' connection you don't accidentally fall through and try to handle the response twice.
Also, you don't have to explicitly call 'start' on an NSURLConnection unless you pass NO to the startImmediately: parameter in the constructor. That shouldn't cause a problem though.
i am using singleton class for web service calling and display in uitableview ,My function is when i clicked submit button of new orchardname for new add then view redirect to tableview but data not seen which add recently. "singOrchard.orcharsList" it's orchard name array which i have to display. "[wOrchrad getorchardslist]" it's my web service call.
- (IBAction)Submit:(id)sender
{
if (Orchadname.text.length == 0) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"DataTree" message:#"Please Enter OrchardName" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[message show];
}
else {
[singOrchard.orcharsList removeAllObjects];
NSString *urlStr = [NSString stringWithFormat:#"http://xyz.com"]; // Passing token to URL
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:req delegate:self]; // Support to perform URLrequest
if (theConnection) { // checking connection successfull or not
webData1 = [NSMutableData data];
NSLog(#"Orchard Name is %#", Orchadname.text);
}
[wOrchrad getorchardslist];
NSLog(#"ARRAY COUNT %#",singOrchard.orcharsList);
[self performSelector:#selector(gotodetails) withObject:nil afterDelay:4];
}
}
"[wOrchard getorchardslist]- Singletone+Webserviceutility"
- (void)getorchardslist
{
orchardsnames = [[NSMutableArray alloc] init];
singltoneclass = [SingletoneClass sharedInstanceMethod];
theRequest =[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.xyz.com"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
webData = [NSMutableData data];
[theConnection start];
}
You are not using the return result from theConnection. (At least not in your provided code.) Since you have set your class as the delegate, implement the NSURLConnectionDataDelegate methods.
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
use it to save your JSON data to an NSArray, which you can then use in your UITableView.
If you send your request asynchrounsly, don't forget to append the data with
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
I am making an iPhone app that will need to communicate with the Sendy API. I believe that it uses some kind of JSON, but I'm not really sure, nor do I know where to start. I'm particularly interested in the subscribe portion of the API. Basically, I need to know how to talk to the Sendy API from my app.
Any help is appreciated.
My code:
- (IBAction)submitButtonPressed:(id)sender
{
self.data = [[NSMutableData alloc] initWithLength:0];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.erwaysoftware.com/sendy/subscribe"]];
[request setHTTPMethod:#"POST"];
[request setValue:#"john#test.com" forHTTPHeaderField:#"email"];
[request setValue:#"john" forHTTPHeaderField:#"name"];
[request setValue:#"LxxxxxxxxxxxxxxxxxxxxQ" forHTTPHeaderField:#"list"];
[request setValue:#"true" forHTTPHeaderField:#"boolean"];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:request delegate:self];
[conn start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.data setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d {
[self.data appendData:d];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Error", #"")
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", #"")
otherButtonTitles:nil] show];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];
// Do anything you want with it
NSLog(#"%#", responseText);
}
When the log happens, the string is empty. I know through breakpoints that the last method is called.
Looking at the API it's all just plain text response.
Since it's a POST you can use an NSURLConnection to compose the request. See this question for information on formatting the response.
An alternative is to use something like AFNetworking or RestKit that might be a little more friendly if you're doing more work with APIs.
I'm guessing you've already resolved this but in case anyone else gets stuck here (as I did) I thought I'd post what I did to get it to work.
The first thing you need to do is create a category called NSString+URLEncoding (or whatever) which is going to take your email and name fields from blah#blah.com and turn it into blah%40blah.com. I modified this from the handy blog post found here
#interface NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding;
#end
#import "NSString+URLEncoding.h"
#implementation NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding)));}
#end
Ok so now just import NSString+URLEncoding.h and add the following code and you'll be in business. This post helped me with this part
- (IBAction)submitButtonPressed:(id)sender
{
NSMutableURLRequest *newRequest = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:#"http://stashdapp.com/sendy/subscribe"]];
[newRequest setHTTPMethod:#"POST"];
[newRequest setValue:#"application/x-www-form-urlencoded; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
NSString *email = #"name#domain.com";
NSString *name = #"First Lastname";
NSString *list = #"XXXXXXXXXXXXXXXXXX";
NSString *postData = [NSString stringWithFormat:#"email=%#&boolean=true&name=%#&list=%#", [email urlEncodeUsingEncoding:NSUTF8StringEncoding],[name urlEncodeUsingEncoding:NSUTF8StringEncoding],list];
[newRequest setHTTPBody:[postData dataUsingEncoding:NSUTF8StringEncoding]];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:newRequest delegate:self];
[conn start];
}
You still include the delegate methods which you quoted in your question.
Hope it helps someone!
I am trying to send a simple NSURLConnection request:
- (void) sendHTTPRequest:(NSString*)urlString
{
NSLog(#"SendHTTPRequest: %#", urlString);
#try
{
NSURL *fileURL = [NSURL fileURLWithPath:urlString];
// Create the request.
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
receivedData = [NSMutableData data];
}
else {
// Inform the user that the connection failed.
}
}
#catch (NSException *e)
{
NSLog(#"Exception: %#", e);
}
}
It calls back to:
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
with an error of: Connection failed! Error - The requested URL was not found on this server.
However, this url does work. I can access it with my browser with no issues.
What am I missing?
According to the NSURL Class Reference, fileURLWithPath:path is only used for valid system paths. For "Internet"-URLs, you are supposed to use [NSURL urlWithString:urlString];