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];
Related
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.
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 working on the google maps where I find the location based on the text entered in the
textfield.I have used NSConnection to find the location json and then I assign this json to
the property in connectionDidFinishLoading delegate method so that I can access the json
when it is required but unfortunately I am not getting the data in geocodeAddress
method(NSLog(#"geodata %#",geocode))
Can any one help me to fix this issue?
- (void)geocodeAddress:(NSString *)address withCallback:(SEL)callback withDelegate: (id)delegate
{
NSString *geocodingBaseUrl = #"http://maps.googleapis.com/maps/api/geocode/json?";
NSString *url = [NSString stringWithFormat:#"%#address=%#&sensor=false", geocodingBaseUrl,address];
NSLog(#"url=%#",url);
url = [url stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
NSURL *queryUrl = [NSURL URLWithString:url];
NSURLRequest *request =[NSURLRequest requestWithURL:queryUrl cachePolicy:NSURLCacheStorageNotAllowed timeoutInterval:10];
//NSURLRequest *request =[NSURLRequest requestWithURL:url];
downloaddata= [[NSMutableData alloc]init];
NSURLConnection *connection =[[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"geodata %#",geocode);
//[delegate performSelector:callback];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSError *error;
alldata = [NSJSONSerialization
JSONObjectWithData:self->downloaddata
options:NSJSONReadingMutableContainers
error:&error];
if(error)
{
}
else
{
self.geocode =alldata;
//NSLog(#"geodata %#",geocode);
}
}
NSURLConnection's are normally asynchronous, so geocode isn't set until the connectionDidFinishLoading is called, which won't happen until sometime after geocodeAddress... has finished. In your connectionDidFinishLoading... you'll need to execute code to cause the UI to refresh with the now valid geocode data.
Alternatively you could use + (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error to execute the request synchronously, but that would be bad since it would block the UI until the request completed.
I need some help. I am calling the login function from another class,
// Login on server
- (BOOL) login:(NSString*) username password:(NSString*)password
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:subscribedAppsURL]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connectionDict setObject:connection forKey:#"login"];
[connection release];
return true;
}
// delegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished Loading");
if (connection == [connectionDict objectForKey:#"login"]) {
[connection release];
//#TODO Here I want to function login to return true.
}
}
At the end of connectionDidFinishLoading I want to return the TRUE/ FALSE value in the function login. Does anyone have some suggestions? Thanks!
You can send your request synchronously like this:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:subscribedAppsURL]];
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if (error != nil)
{
NSString *stringResponse = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"Reponse:%#", response);
//Handle the response, possible just return true here:
}
else
{
NSLog(#"Error:%#", error.localizedDescription);
}
With the intent of using delegates:
//In Header
#protocol LoginCompletionDelegate
-(void) didCompleteAndIsLoggedIn:(BOOL) loggedIn;
#end
#property (nonatomic, assign) id<LoginCompletionDelegate> delegate;
//In implementation
- (BOOL) loginWithDelegate:(id<LoginCompletionDelegate>)target username:(NSString*) username password:(NSString*)password
{
delegate = target;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:subscribedAppsURL]];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connectionDict setObject:connection forKey:#"login"];
[connection release];
return true;
}
// delegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished Loading");
if (connection == [connectionDict objectForKey:#"login"]) {
[connection release];
//#TODO Here I want to function login to return true.
[delegate didCompleteAndIsLoggedIn:YES];
}
}
//There is another method that looks like this. I might have the signature a bit wrong
-(void) connection:(NSURLConnection*) connection didFailWithError:(NSError*) error
{
[delegate didCompleteAndIsLoggedIn:NO];
}