views:

138

answers:

1

hello -

I was previously downloading images for my app by using dataWithContentsOfURL to download a jpg then writeToFile to save it.

I recent;y started using an NSURLConnetion to do the same, but now I am getting the follwoing errors and a crash:

Corrupt JPEG data: 87 extraneous bytes JPEG datastream contains no image

I know these images are not corrumpt, as the app was downloading them fine using the previous method. Here is my code:

-(void) downloadSave {

    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

    NSString *tempString = [[NSString alloc]initWithFormat:@"http://www.mysite.com/%@.jpg",chartFileName];
    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:tempString]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:10.0];
    // 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.
        mutableData = [[NSMutableData data] retain];
        self.image = nil;
        NSLog(@"connection exists");
        [NSURLConnection connectionWithRequest:theRequest delegate:self];

    } else {
        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Connection Error" message:@"There was an error contacting the chart servers. Please try again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
        [activityIndicator stopAnimating];


    }




//  NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
//                                                       NSUserDomainMask, YES);

//  NSString *docsPath = [paths objectAtIndex:0];
//  NSString *downloadPath = [[[NSString alloc]initWithFormat:@"http://www.mysite.com/%@.jpg",chartFileName]autorelease];
//  downloadedChartData = nil;


    [pool drain];
    [pool release];




}


- (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.
    NSLog(@"got to connection did receive response");
    [mutableData setLength:0];
}




- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    // Append the new data to receivedData.
    // receivedData is an instance variable declared elsewhere.
    [mutableData appendData:data];
//  NSLog(@"got some data, total: %i",mutableData.length);
}


- (void)connection:(NSURLConnection *)connection
  didFailWithError:(NSError *)error
{
    // release the connection, and the data object
 //   [connection release];
    // receivedData is declared as a method instance elsewhere
   // self.mutableData = nil;

    // inform the user
    //NSLog(@"Connection failed! Error - %@ %@",
      //    [error localizedDescription],
        //  [[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // do something with the data
    // receivedData is declared as a method instance elsewhere
    NSLog(@"Succeeded! Received %d bytes of data",[mutableData length]);
    [connection release];
    // release the connection, and the data object
    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask, YES);
    NSString *docsPath = [paths objectAtIndex:0];
    self.image = nil;

    NSString *savePath = [[[NSString alloc]initWithFormat:@"%@/%@.jpg",docsPath, chartFileName]autorelease];

    [mutableData writeToFile:savePath atomically:YES];
    self.mutableData = nil;
+7  A: 

You are initializing and starting two NSURLConnections with the same delegate. As your delegate methods do not check which connection called them you are mixing up the bytes of two times your image in one NSMutableData instance.

// Creates, initializes and starts an instance of NSURLConnection    
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
...
// Creates, initializes and starts another instance of NSURLConnection, with same request and delegate
[NSURLConnection connectionWithRequest:theRequest delegate:self];

Both connections message the same implementations on the same delegate instance, which means their data is written into the same NSMutableData in random order.

I would suggest to simply get rid of the line:

[NSURLConnection connectionWithRequest:theRequest delegate:self];

Another thing: why are you using an autorelease pool in downloadSave? If you call it from the main Thread you have only one NSURLRequest autoreleased in that pool. If you call it from an other Thread you have to take care, that the runloop of that thread is setup and running, or you wouldn't receive any delegate callbacks at all.

tonklon