paxx
paxx

Reputation: 1079

NSURLConnection sends data twice

I'm uploading image to my server and while I'm uploading image I'm trying to show user a progress bar of the upload. But in a NSURLConnection delegate method connection: didSendBodyData: totalBytesWritten: totalBytesExpectedToWrite: I get confusing numbers. Lets say my data is X bytes long. At first I get totalBytesExpectedToWrite to be X, but then after totalBytesWritten reaches totalBytesExpectedToWrite my connection still progresses with upload and totalBytesExpectedToWrite shift to 2X. It's always exactly 2X and I don't know why. Connection is the same (by id) and I invoke it only once.

Here is my code for uploading image:

- (void)uploadImage:(UIImage *)image
{ 
// random boundary string
NSString *boundary = @"----8745633765875256----";

NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
NSMutableData *requestData = [[NSMutableData alloc] init];

// append boundary and separate it with new line
[requestData appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];

// setting up header files, appending image and separating body with boundary
[requestData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"ad_image\"; filename=\"%@\"\r\n", @"tmp.jpg"] dataUsingEncoding:NSUTF8StringEncoding]];
[requestData appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
[requestData appendData:imageData];
[requestData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];  

// initializing request
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@&user_id=%@&api_key=%@", kUrlImageTempAdd, userID, apiKey]]];
[request setHTTPMethod:@"POST"];

// setting up content-type "form" to multipart/form-data for image upload
[request addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:requestData];

//setting up content length
[request setValue:[NSString stringWithFormat:@"%d", [requestData length]] forHTTPHeaderField:@"Content-

// connection init and start
NSURLConnection *connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:true] autorelease];
}

and here is my delegate method:

- (void)connection:(NSURLConnection *)connection
didSendBodyData:(NSInteger)bytesWritten
totalBytesWritten:(NSInteger)totalBytesWritten
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
{
NSLog(@"connection %@ bytes sent %d/%d (%f%%)", connection, totalBytesWritten, totalBytesExpectedToWrite, ((float)totalBytesWritten / (float)totalBytesExpectedToWrite) * 100.0f);
}

Any suggestions why this is happening? I'm losing my mind over here :)

Upvotes: 2

Views: 1839

Answers (2)

Ken Thomases
Ken Thomases

Reputation: 90601

The documentation for -connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: says

The value of totalBytesExpectedToWrite may change during the upload if the request needs to be retransmitted due to a lost connection or an authentication challenge from the server.

(The documentation for the NSURLConnection delegate methods seems to have been largely lost when it transitioned from being an informal to a formal protocol. You can check the comments in the header or have Xcode download one of the older docsets and check there.)

You can implement some of the other delegate methods to observe what might be happening, like an authentication challenge.

Upvotes: 3

Lefteris
Lefteris

Reputation: 14677

The delegate method you are using can be called a lot of times, as it reports status updates on the data upload to the server...

The NSURLConnection object will transfer the data to the server in packet of bytes and each time a packet is sent it will call the delegate method.

If you only want to know when the upload did end you need to use this delegate method:

- (void)connectionDidFinishLoading:(NSURLConnection *)connection

See more in the official documentation of the NSURLDownloadDelegate delegate

Upvotes: 1

Related Questions