2

I'm kinda of new at ios development, I've been reading and searching but cannot find a working example or an example of how to upload a file from iphone to webserver asychronously..

I'm able to upload synchronously using

[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

it works, but it blocks my main thread.

NSUrlConnection has this delegate (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:)

but I've no idea how to implement it.

Can someone please point me in the right direction?

Mat
  • 202,337
  • 40
  • 393
  • 406
skeo
  • 175
  • 1
  • 1
  • 11
  • I suggest you to create new Thread where you will execute `[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];`. – Nekto Sep 01 '11 at 05:44
  • I have considered creating a thread for each upload, but then how would I get feedback as to the success or failure of the upload? – skeo Sep 01 '11 at 06:29

3 Answers3

13

I have managed to get uploading to work with NSURLConnection asynchronously with this:

-(NSURLRequest *)postRequestWithURL: (NSString *)url

                                data: (NSData *)data   
                            fileName: (NSString*)fileName
{

// from http://www.cocoadev.com/index.pl?HTTPFileUpload

    //NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];

    NSMutableURLRequest *urlRequest = [[[NSMutableURLRequest alloc] init] autorelease];
    [urlRequest setURL:[NSURL URLWithString:url]];
    //[urlRequest setURL:url];

    [urlRequest setHTTPMethod:@"POST"];

    NSString *myboundary = [NSString stringWithString:@"---------------------------14737809831466499882746641449"];
    NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",myboundary];
    [urlRequest addValue:contentType forHTTPHeaderField: @"Content-Type"];


    //[urlRequest addValue: [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundry] forHTTPHeaderField:@"Content-Type"];

    NSMutableData *postData = [NSMutableData data]; //[NSMutableData dataWithCapacity:[data length] + 512];
    [postData appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", myboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n", fileName]dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postData appendData:[NSData dataWithData:data]];
    [postData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", myboundary] dataUsingEncoding:NSUTF8StringEncoding]];

    [urlRequest setHTTPBody:postData];
    return urlRequest;
}

usage is as follows:

    NSURLRequest *urlRequest = [self postRequestWithURL:urlString
                                                   data:aVideo.msgvid
                                               fileName:filename];

    uploadConnection =[[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
Alex Zielenski
  • 3,591
  • 1
  • 26
  • 44
skeo
  • 175
  • 1
  • 1
  • 11
5

Threading is not necessary for this kind of problem. I would suggest you use the asynchronous functionality built into NSURLConnection:

NSURLConnection *connection = [NSURLConnection initWithRequest:request delegate:self];
[connection start];


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //Get your response, do stuff
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    //Show error, retry, etc
}

EDIT: If you are really looking to upload a file and want to display a progress bar, then you should look at ASIHTTPRequest framework, which you can find more info on here: http://allseeing-i.com/ASIHTTPRequest/

For uploading a POST request with data using ASIHTTPRequest, you would do:

NSURL *url = [NSURL URLWithString:@"YOUR_URL_HERE"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"123" forKey:@"user_id"];
[request setData:someData withFileName:@"someData.jpg" andContentType:@"image/png" forKey:@"image"];
[request setProgressDelegate:self];
[request setDelegate:self];
[request startAsynchronous];

Again, refer to the link above for the framework and documentation. I highly recommend it.

Nicolas Renold
  • 557
  • 2
  • 5
  • Nick, could you please elaborate more on NSURLConnection to say: sending an NSData or jpeg file via this way? I'm able to download asynchronously using this method, but it beyond me how I would set the wrappers up for a file upload. If all else fails, I will take a look at ASIHTTPResquest – skeo Sep 01 '11 at 06:58
  • 1
    I would include sample code for NSURLConnection with NSData, but I have not done that since I have always needed multipart-formdata, which is a nightmare with NSURLConnection. – Nicolas Renold Sep 01 '11 at 07:09
  • one more stupid question if I may Nick. I am following the ASIHttprequest method, now in the delegate [request setDidFinishSelector:@selector(uploadRequestFinished:)]; how would I change this to be able to pass in an extra variable? say an nsstring? – skeo Sep 01 '11 at 08:05
2

You cant create new thread for that task:

[NSThread detachNewThreadSelector:@selector(upload:) toTarget:self withObject:data];

And when you will finish uploading, just call some implemented method in your main thread (for example uploaded):

[self performSelectorOnMainThread:@selector(uploaded) withObject:nil waitUntilDone:NO];
Nekto
  • 17,837
  • 1
  • 55
  • 65