Upload and download data from server with Cocoa Touch? - ios

How can I upload/download data from a server in Cocoa Touch. Here's what I have so far...
-(void)uploadSchedule:(id)sender
{
NSData *content = [NSData dataWithContentsOfFile:self.dataFilePath];
NSString *stuff = [[NSString alloc] initWithData:content encoding:NSASCIIStringEncoding];
NSURL *url = [NSURL URLWithString:#"http://thetis.lunarmania.com"];
NSMutableURLRequest* urlRequest = [[NSMutableURLRequest alloc]initWithURL:url];
[urlRequest setHTTPMethod:#"POST"];
[urlRequest setHTTPBody:[stuff dataUsingEncoding:NSASCIIStringEncoding]];
NSLog(#"great success!");
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// this method is called when the server has determined that it
// has enough information to create the NSURLResponse
// it can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is declared as a method instance elsewhere
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
UIImage *image = [[UIImage alloc] initWithData:receivedData];
[cat setImage:image];
[image release];
// receivedData is declared as a method instance elsewhere
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// release the connection, and the data object
[connection release];
[receivedData release];
}
-(void)connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential;
newCredential=[NSURLCredential credentialWithUser:#"ican#moeyo.org"
password:#"icanican"
persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential
forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password
// in the preferences are incorrect
//[self showPreferencesCredentialsAreIncorrectPanel:self];
}
}
I'm so lost...

The code crashes because you over-release connection. Review the Cocoa memory management rules.
Aside from that, you'll have to be more specific about what problem you're having with it.
BTW, the term is “instance variable”, not “method instance”. An instance variable is a variable inside of an instance, and has nothing to do with methods.

This has been covered here:
NSURLRequest - encode url for NSURLRequest POST Body (iPhone objective-C)
The accepted answer uses ASIHTTPRequest which is similar to one I've used, and makes it really easy to post/get from an HTML form. Here's an example (from past stackoverflow)
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:#"http://someSite.com"] autorelease];
[request setPostValue:#"myValue1" forKey:#"myFormField1"];
[request setPostValue:#"myValue2" forKey:#"myFormField2"];
// etc.
[request start];
NSError *error = [request error];
if (!error)
NSString *response = [request responseString];

And if your file is big, you should better use NSFilehandle, to write data inside didReceiveData, instead of appending.

Related

Same code showing different behaviour in XCode

-(IBAction)onButtonClick:(id)sender
{
DowloadFilesManager* downManager1=[[DowloadFilesManager alloc] init];
DowloadFilesManager* downManager2=[[DowloadFilesManager alloc] init];
DowloadFilesManager* downManager3=[[DowloadFilesManager alloc] init];
[downManager1 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat.jpg"];
[downManager2 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat1.jpg"];
[downManager3 downloadURL:#"http://localhost/banners/banner1.jpg" destPath:#"/Users/varunisac/Desktop/samples/godisgreat2.jpg"];
NSLog(#"Finished Succesfully");
}
1)The Above code works Perfect
2) It downloads the jpgs after firing the following event function.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[receivedData writeToFile:toFile atomically:YES];
theConnection = nil;
receivedData = nil;
}
But It DOES NOT fires any event methods while i tried on another programme after importing the "DowloadFilesManager.h" and "DowloadFilesManager.m" which runs on the same XCode on the same Mac machine with the server URLs reachable.Can anyone suggest a solution ? Am i missing anything? I tried Clean etc...but doesnt work. Following is the DowloadFilesManager class which i used:
#import "DowloadFilesManager.h"
#implementation DowloadFilesManager
#synthesize toFile;
#synthesize toURL;
#synthesize theConnection;
-(void) downloadURL:(NSString *) urlStr destPath:(NSString *) destPath
{
toURL=urlStr;
toFile=destPath;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:toURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
receivedData = [[NSMutableData alloc] init];
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
// [receivedData dataWithCapacity: 0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (!theConnection) {
// Release the receivedData object.
receivedData = nil;
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
theConnection = nil;
receivedData = nil;
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
[receivedData writeToFile:toFile atomically:YES];
theConnection = nil;
receivedData = nil;
}
#end
Within - (void)downloadURL:destPath:, you have created a local variable called theConnection:
NSURLConnection *theConnection = [...];
and when the method ends, this will go out of scope and be destroyed.
What you want is the following, to use your property to persist the connection object:
self.theConnection = [...];
Also, a better approach to signal failure would be to make that method return BOOL and use this statement:
return self.theConnection != nil;

send date to server and get a string back

I'm sending to my server user detail and it is supposed to return a user id as a string,
the data received at my server bat I can get the string.
The code:
NSString *urlStr = [NSString stringWithFormat:#"url/////api/%#/%#",
[Email.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[Password.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
nil];
NSString *content = #"field1=42&field2=Hello";
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlStr]];
[request setHTTPMethod:#"GET"];
[request setHTTPBody:[content dataUsingEncoding:NSISOLatin1StringEncoding]];
[NSURLConnection connectionWithRequest:request delegate:self];
NSURLConnection *connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
if (connection) {
NSLog(#"good conection");
[_receivedData appendData:_data];
NSString *DataString = [[NSString alloc] initWithData:_receivedData encoding:NSUTF8StringEncoding];
NSLog(#"foo1: %#", DataString);
NSLog(#"foo2: %#", _receivedData);
}
2014-01-03 22:27:57.322 App[962:70b] foo1:
2014-01-03 22:27:57.323 App[962:70b] foo2: (null)
Implement following NSURLConnection delegate to fetch data asynchronously.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
// 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
_responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
// 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 {
// The request is complete and data has been received
// You can parse the stuff in your instance variable now
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
// The request has failed for some reason!
}

how to wait the response from a http request in ios

Anybody knows how to wait the response of a http request? In my code, I am doing a http request to an url and then what i need to do, it is to check the http response in order to decide different treatment. I have something like this:
-(void)check{
[self fetchURL:#"http://something"];
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
}
-(void)fetchURL:(NSString *)urlWeb{
NSURL *url = [NSURL URLWithString:urlWeb];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSLog(#"INSIDE OF didReceiveResponse");
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"INSIDE OF didFailWithError");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"INSIDE OF connectionDidFinishLoading");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
NSLog(#"inside of didReceiveData");
response = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"response: %#", response);
}
I have been trying different options that I have seen around here, but i cant stop the execution of my code and wait for that answer...that means when I check the response of my http request, it always appears empty or with a nil reference...
any help how to figure out??
thanks
You can't evaluate the response value right after your 'fetchUrl' call, because your request is asynchronous, and your code goes on with the execution without waiting for the answer. You will receive the response value only in one of the delegate method, so there's the place where you should check the result.
If you really want to make a synchronous request you can use sendSynchronousRequest:returningResponse:error: like this
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if(data){
//use data
}
else{
//check error domain and code
}
(See the Apple NSURLConnection Reference)
But keep in mind that your program will be stuck on this call till it receives a response or goes timeout.
Why don't you write this code:
if(response != nil || [response length] != 0){
do something....
}
else{
do something else....
}
In - (void)connectionDidFinishLoading:(NSURLConnection *)connection; method it wouldn't execute unless you have your complete proper response.
And Just for ado: Right to way to get data properly should be:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[_responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSString *string = [[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
if (string)
NSLog(#"string = %#", string);
}
Did you try checking the respons witin connectionDidFinishLoading: ?
That is the very delegate method which is called when the data was transferred successfully. Before that point in time, you should not expect any meaningful data.
Besides - didReceiveData should provide you with portions of data received in the meantime. Apparently you do not seem to process it nor just to store it for later evaluation (witin connectionDidFinishLoading)

NSURLConnection - didReceiveData didn't get called - iOS & ARC

I'm currently experimenting with the twitter streaming api and i'm trying to get a stream with NSURLConnection. As it doesn't work with twitter, i simplified everything and tried to get some source-code out of google's website, but this doesn't work neither.
The connection starts and ends, but without calling the didReceiveData delegate. I'm sure i'm missing something. Hope you guy's can help me!
In the header: #interface ViewController : UIViewController <NSURLConnectionDataDelegate, NSURLConnectionDelegate, NSURLConnectionDownloadDelegate, NSURLAuthenticationChallengeSender>
And in the body:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLConnection *connection;
NSMutableURLRequest *request;
// Do any additional setup after loading the view, typically from a nib.
request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[request setHTTPMethod:#"GET"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
NSLog(#"Stream finished.");
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"Connection failed!");
}
A couple of thoughts.
Your declaration of connectionDidFinishLoading doesn't look right. The standard NSURLConnectionDataDelegate method does not have a destinationURL parameter:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
Given the presence of NSURLAuthenticationChallengeSender, if you're expecting a challenge (which you won't get with Google web site) then you'd obviously handle it accordingly:
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
// For example, if you have a userid/password to use, see if this is the first
// challenge, and then tell NSURLConnection to try using those credentials, and if
// it failed a second time, you might just cancel the authentication challenge.
if (challenge.previousFailureCount == 0) {
NSURLCredential *credential = [NSURLCredential credentialWithUser:kUserID password:kPassword persistence:NSURLCredentialPersistenceForSession];
[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
}
}
By the way, you do not want to call start method when you use initWithRequest or connectionWithRequest. It's only needed if you do a simple initWithRequest:delegate:startImmediately: and instruct it to not startImmediately.
Anyway, I used the following and it works fine:
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"%s", __FUNCTION__);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%s: %#", __FUNCTION__, dataString);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"%s error=%#", __FUNCTION__, error);
}
Someone said here that it was their SOAP format
NSURLConnection delegate method: didReceiveData not called ...Why ?? (iPhone SDK)
This also may be what you are looking for
NSURLConnection didReceiveData not called
Your NSURLConnection local variable connection is going out of scope at the end of viewDidLoad. Add a property to your ViewController to hold the NSURLConnection variable in scope.

Image blank when using NSURLConnection but not when using dataWithContentsOfURL

When I use NSURLConnection asynchronously to try and get a NSData with my image data in it the image comes back as blank, but when I use dataWithContentsOfURL synchronously I have no problems and I get the image data correctly. Is there any reason why my asynchronous method would be failing?
This works:
NSData *data = [NSData dataWithContentsOfURL: url];
NSLog(#"TEST %#", data);
UIImage *map = [UIImage imageWithData:data];
mapView.image = map;
This doesn't:
//
// MapHttpRequest.m
// GTWeb
//
// Created by Graphic Technologies on 6/21/11.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "MapHttpRequest.h"
#implementation MapHttpRequest
#synthesize receivedData;
#synthesize dataString;
#synthesize vc;
- (void)request:(NSString *)url fromView:(UIViewController *) theVC
{
vc = theVC;
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
NSLog(#"URL: %#", url);
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
// receivedData is an instance variable declared elsewhere.
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
// receivedData is an instance variable declared elsewhere.
[receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data
// receivedData is declared as a method instance elsewhere
[vc mapImageConnectionFinished:receivedData];
// release the connection, and the data object
[dataString release];
[connection release];
[receivedData release];
}
#end
It looks like you started looking at the guide on http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html but didnt finish reading it :)
You need to implement the methods that will received infomation about the data being received.
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
Its all described in the link i provided.
According to your code, you didn't schedule the connection to run:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
Did you put traces in your delegate's callbacks to make sure they are being called?
Turns out it was giving me a bad request because there was a invisible carriage return or white space. Trimming it off with:
url = [url stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
fixed my problems.

Resources