Sunday, April 8, 2012

How to download a large file with the iPhone SDK and avoid memory usage issues?


I'm using the NSURLConnection class to download a large file in my iPhone application, but it crashes every so often because it's using too much memory. I'm doing the usual NSURLConnection usage, to append the received data to a NSMutableData object.




- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.fileData appendData:data];
}



Then after I finish downloading the whole file, I save it to a local temporary file, and read it as a mapped file like this:




- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
// save the downloaded data into a temporary file
NSString *tempPath = NSTemporaryDirectory();
NSString *tempFile = [tempPath stringByAppendingPathComponent:@"temp.pdf"];
[self.fileData writeToFile:tempFile atomically:YES];
NSData *mappedData = [NSData dataWithContentsOfMappedFile:tempFile];

NSURL *baseURL = [NSURL URLWithString:@"http://mydomain.com"];
[webView loadData:mappedData MIMEType:@"application/pdf" textEncodingName:@"UTF-8" baseURL:baseURL];
}



What can I improve here to avoid these memory usage problems?


Source: Tips4all

3 comments:

  1. If it's that large, why not write it to the file as it comes in, rather than keeping it in an NSData object?

    ReplyDelete
  2. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response {

    filename = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:save_name]; // filename is in .h file

    [[NSFileManager defaultManager] createFileAtPath:filename contents:nil attributes:nil];
    file =
    [[NSFileHandle fileHandleForUpdatingAtPath:filename] retain];// file is in .h

    if (file) {

    [file seekToEndOfFile];
    }
    }

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSD
    ata *)data {

    if (file) {

    [file seekToEndOfFile];

    } [file writeData:data];

    }

    - (void)connectionDidFinishLoading:(NSURLConnection*)connection {

    [file closeFile];

    }

    ReplyDelete
  3. i'm using

    - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
    {
    filename = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:save_name];
    NSFileHandle *file1 = [NSFileHandle fileHandleForUpdatingAtPath: filename];
    [file1 writeData: data];
    [file1 closeFile];
    }

    ReplyDelete