title: Downloading a Large File - iPhone SDK
body: <p>I am using Erica Sadun's method of Asynchronous Downloads (link here for the project file: <a href="http://uhelios.com/downloaderica.zip" rel="noreferrer">download</a>), however her method does not work with files that have a big size (50 mb or above). If I try to download a file above 50 mb, it will usually crash due to a memory crash. Is there anyway I can tweak this code so that it works with large files as well? Here is the code I have in the DownloadHelper Classes (which is already in the download link):</p>
  
  <p>.h</p>
  
  <pre><code>@protocol DownloadHelperDelegate &lt;NSObject&gt;
  @optional
  - (void) didReceiveData: (NSData *) theData;
  - (void) didReceiveFilename: (NSString *) aName;
  - (void) dataDownloadFailed: (NSString *) reason;
  - (void) dataDownloadAtPercent: (NSNumber *) aPercent;
  @end
  
  @interface DownloadHelper : NSObject 
  {
      NSURLResponse *response;
      NSMutableData *data;
      NSString *urlString;
      NSURLConnection *urlconnection;
      id &lt;DownloadHelperDelegate&gt; delegate;
      BOOL isDownloading;
  }
  @property (retain) NSURLResponse *response;
  @property (retain) NSURLConnection *urlconnection;
  @property (retain) NSMutableData *data;
  @property (retain) NSString *urlString;
  @property (retain) id delegate;
  @property (assign) BOOL isDownloading;
  
  + (DownloadHelper *) sharedInstance;
  + (void) download:(NSString *) aURLString;
  + (void) cancel;
  @end
  </code></pre>
  
  <p>.m</p>
  
  <pre><code>#define DELEGATE_CALLBACK(X, Y) if (sharedInstance.delegate &amp;&amp; [sharedInstance.delegate respondsToSelector:@selector(X)]) [sharedInstance.delegate performSelector:@selector(X) withObject:Y];
  #define NUMBER(X) [NSNumber numberWithFloat:X]
  
  static DownloadHelper *sharedInstance = nil;
  
  @implementation DownloadHelper
  @synthesize response;
  @synthesize data;
  @synthesize delegate;
  @synthesize urlString;
  @synthesize urlconnection;
  @synthesize isDownloading;
  
  - (void) start
  {
      self.isDownloading = NO;
  
      NSURL *url = [NSURL URLWithString:self.urlString];
      if (!url)
      {
          NSString *reason = [NSString stringWithFormat:@"Could not create URL from string %@", self.urlString];
          DELEGATE_CALLBACK(dataDownloadFailed:, reason);
          return;
      }
  
      NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
      if (!theRequest)
      {
          NSString *reason = [NSString stringWithFormat:@"Could not create URL request from string %@", self.urlString];
          DELEGATE_CALLBACK(dataDownloadFailed:, reason);
          return;
      }
  
      self.urlconnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
      if (!self.urlconnection)
      {
          NSString *reason = [NSString stringWithFormat:@"URL connection failed for string %@", self.urlString];
          DELEGATE_CALLBACK(dataDownloadFailed:, reason);
          return;
      }
  
      self.isDownloading = YES;
  
      // Create the new data object
      self.data = [NSMutableData data];
      self.response = nil;
  
      [self.urlconnection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
  }
  
  - (void) cleanup
  {
      self.data = nil;
      self.response = nil;
      self.urlconnection = nil;
      self.urlString = nil;
      self.isDownloading = NO;
  }
  
  - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)aResponse
  {
      // store the response information
      self.response = aResponse;
  
      // Check for bad connection
      if ([aResponse expectedContentLength] &lt; 0)
      {
          NSString *reason = [NSString stringWithFormat:@"Invalid URL [%@]", self.urlString];
          DELEGATE_CALLBACK(dataDownloadFailed:, reason);
          [connection cancel];
          [self cleanup];
          return;
      }
  
      if ([aResponse suggestedFilename])
          DELEGATE_CALLBACK(didReceiveFilename:, [aResponse suggestedFilename]);
  }
  
  - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData
  {
      // append the new data and update the delegate
      [self.data appendData:theData];
      if (self.response)
      {
          float expectedLength = [self.response expectedContentLength];
          float currentLength = self.data.length;
          float percent = currentLength / expectedLength;
          DELEGATE_CALLBACK(dataDownloadAtPercent:, NUMBER(percent));
      }
  }
  
  - (void)connectionDidFinishLoading:(NSURLConnection *)connection
  {
      // finished downloading the data, cleaning up
      self.response = nil;
  
      // Delegate is responsible for releasing data
      if (self.delegate)
      {
          NSData *theData = [self.data retain];
          DELEGATE_CALLBACK(didReceiveData:, theData);
      }
      [self.urlconnection unscheduleFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
      [self cleanup];
  }
  
  - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
  {
      self.isDownloading = NO;
      NSLog(@"Error: Failed connection, %@", [error localizedDescription]);
      DELEGATE_CALLBACK(dataDownloadFailed:, @"Failed Connection");
      [self cleanup];
  }
  
  + (DownloadHelper *) sharedInstance
  {
      if(!sharedInstance) sharedInstance = [[self alloc] init];
      return sharedInstance;
  }
  
  + (void) download:(NSString *) aURLString
  {
      if (sharedInstance.isDownloading)
      {
          NSLog(@"Error: Cannot start new download until current download finishes");
          DELEGATE_CALLBACK(dataDownloadFailed:, @"");
          return;
      }
  
      sharedInstance.urlString = aURLString;
      [sharedInstance start];
  }
  
  + (void) cancel
  {
      if (sharedInstance.isDownloading) [sharedInstance.urlconnection cancel];
  }
  @end
  </code></pre>
  
  <p>And finally this is how I write the file with the two classes above it:</p>
  
  <pre><code>- (void) didReceiveData: (NSData *) theData
  {
      if (![theData writeToFile:self.savePath atomically:YES])
          [self doLog:@"Error writing data to file"];
  
      [theData release];
  
  }
  </code></pre>
  
  <p>If someone could help me out I would be so glad!</p>
  
  <p>Thanks,</p>
  
  <p>Kevin</p>