title: concurrent background downloads on iphone
body: <p>I am trying to create class that will handle multiple downloads at same time (I need to download a lot of small files) and I have problems with "disappearing" connections.</p>
  
  <p>I have function addDonwload that adds url to list of urls to download, and checks if there is free download slot available. If there is one it starts download immediately. When one of downloads finishes, I pick first url form list and start new download.</p>
  
  <p>I use NSURLConnection for downloading, here is some code</p>
  
  <pre><code>- (bool) TryDownload:(downloadInfo*)info
  {
      int index;
      @synchronized(_asyncConnection)
      {
          index = [_asyncConnection indexOfObject:nullObject];
          if(index != NSNotFound)
          {
              NSLog(@"downloading %@ at index %i", info.url, index);
              activeInfo[index] = info;
              NSURLRequest *request = [NSURLRequest requestWithURL:info.url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:15];
  
              [_asyncConnection replaceObjectAtIndex:index withObject:[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:TRUE]];
              //[[_asyncConnection objectAtIndex:i] scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];           
  
              return true;
          }
      }
  
      return false;
  }
  
  - (void)connectionDidFinishLoading:(NSURLConnection*)connection
  {
    [self performSelectorOnMainThread:@selector(DownloadFinished:) withObject:connection waitUntilDone:false];
  }
  
  - (void)DownloadFinished:(id)connection
  {
      NSInteger index = NSNotFound;
      @synchronized(_asyncConnection)
      {
          index = [_asyncConnection indexOfObject:(NSURLConnection*)connection];
      }
  
      [(id)activeInfo[index].delegate performSelectorInBackground:@selector(backgroundDownloadSucceededWithData:) withObject:_data[index]];
      [_data[index] release];
      [activeInfo[index].delegate release];
      @synchronized(_asyncConnection)
      {
          [[_asyncConnection objectAtIndex:index] release];
          [_asyncConnection replaceObjectAtIndex:index withObject:nullObject];            
      }
      @synchronized(downloadQueue)
      {
          [downloadQueue removeObject:activeInfo[index]];
          [self NextDownload];
      }
  }
  
  - (void)NextDownload
  {
      NSLog(@"files remaining: %i", downloadQueue.count);
      if(downloadQueue.count &gt; 0)
      {
          if([self TryDownload:[downloadQueue objectAtIndex:0]])
          {
              [downloadQueue removeObjectAtIndex:0];
          }
      }
  }
  </code></pre>
  
  <p>_asyncConnection is my array of download slots (NSURLConnections)
  downloadQueue is list of urls to download</p>
  
  <p>What happens is, at the beginning everything works ok, but after few downloads my connections start to disappear. Download starts but connection:didReceiveResponse: never gets called. There is one thing in output console that I don't understand I that might help a bit. Normaly there is something like 
  2010-01-24 21:44:17.504 appName[3057:207]
  before my NSLog messages. I guess that number in square brackets is some kind of app:thread id? everything works ok while there is same number, but after some time, "NSLog(@"downloading %@ at index %i", info.url, index);" messages starts having different that second number. And when that happens, I stop receiving any callbacks for that urlconnection. </p>
  
  <p>This has been driving me nuts as I have strict deadlines and I can't find problem. I don't have many experiences with iphone dev and multithreaded apps. I have been trying different approaches so my code is kinda messy, but I hope you will see what I am trying to do here :)</p>
  
  <p>btw is anyone of you know about existing class/lib I could use that would be helpful as well. I want parallel downloads with ability o dynamically add new files to download (so initializing downloader at the beginning with all urls is not helpful for me)</p>