views:

1738

answers:

7

In my iPhone app I want to download multiple files which are on IIS with authentication. On a button click i want to start the downloading process.

I know how to download a file with authentication.

    NSURLRequest* request =
               [NSURLRequest requestWithURL:mMovieURL 
                             cachePolicy:NSURLRequestUseProtocolCachePolicy 
                             timeoutInterval:60.0];
    movieConnection =
            [[NSURLConnection alloc] initWithRequest:request delegate:self ];

and i have couple of delegate methods with the above code.

But how to do it with mutliple downlaods going at the same time.

Thanks,

+5  A: 

I've done this before when I wanted to download 10 XML files at the same time (it was much faster than queuing them to download one after the other). I used the libraries found here:

http://github.com/leonho/iphone-libs/tree/master

They were easy to implement and there's some example code on the front page to get you started.

self.urls = [NSMutableArray arrayWithObjects:
    @"http://maps.google.com/maps/geo?output=json&q=Lai+Chi+Kok,Hong+Kong",
    @"http://maps.google.com/maps/geo?output=json&q=Central,Hong+Kong",
    @"http://maps.google.com/maps/geo?output=json&q=Wan+Chai,Hong+Kong",
    nil];

self.downloads = [[MultipleDownload alloc] initWithUrls: urls];
self.downloads.delegate = self;

Good luck.

nevan
+4  A: 

I'm not familiar with MultipleDownload, but in case it doesn't meet your needs, the issue I take it is that you have a single object that is the delegate to many NSURLConnections, and you want to know how to keep them straight.

The delegate methods all return the NSURLConnection itself as their first parameter. So you can keep track of which data goes where by testing which NSURLConnection is calling you back. One way to do this is with an NSDictionary that maps the connection to its NSMutableData object. Now the trick is that you can't make an NSURLConnection be the key in a dictionary because it doesn't conform to NSCopying (and you wouldn't want it to). One way to work around this is to use the address of the connection such as:

NSString *key = [NSString stringWithFormat:@"%p", connection];

This will return a unique key for any object (the hex representation of its address). Some people use description for this purpose, but I don't like that because it's not a well defined interface. There's no promise that it be unique. In systems where I do this a lot, I implement the above -stringWithFormat: in a method called -uniqueIdentifier and make it a category on NSObject so anything can be tracked in a dictionary.

I often find it's easier just to create a small wrapper object so that each object controls its own NSURLConnection, much as I'm sure MultipleDownload is doing, but still this technique is useful in a variety of cases, whether you're managing multiple tableviews, or anything else that has a delegate.

EDIT: Replaced %x I had above with %p as noted by Peter. He's right, and I wasn't thinking correctly. Double-checking my code, I actually have been using %p, having run into this error before....

Rob Napier
Use %p for pointers, not %x. %x is unsigned int, and a pointer is not guaranteed to be the same size as an int (indeed, on 64-bit versions of Mac OS X, it *is not* the same size).
Peter Hosey
Fixed. Thanks. You're absolutely right.
Rob Napier
+1  A: 

I think the simplest way to do this is to use NSOperation - and a NSOperationQueue.

This will mean that you can specifiy if each operation should happen sequentially or in parallel. You can even limit the number of parallel operations - so that there are a max of 5 (say) running at one time time and then other operations queue up behind.

This really is a great way of letting the OS handle multiple activities - and works well with the lazy loading type philosophy of the iPhone OS.

You can then get each operation to make a call back as it finishes - or even make progress callbacks on the main thread.

I have changed my code to all work this way now and found it to be much more robust and user firendly.

Grouchal
The problem is that nsoperation cannot handle async download which will finish later, not immediately.
iPhoney
I don't think that is correct - I think indeed that is the whole point of NSOperation
Grouchal
A: 

NSURLConnection is asynchronous and init exits immediately. Just run it multiple times.

NSArray *connections = [[NSArray alloc] initWithObjects:
  [[NSURLConnection alloc] initWithRequest:request1 delegate:self ],
  [[NSURLConnection alloc] initWithRequest:request2 delegate:self ],
  [[NSURLConnection alloc] initWithRequest:request3 delegate:self ],
  [[NSURLConnection alloc] initWithRequest:request4 delegate:self ],
  nil];
porneL
I dunno. What if an error happens on one of the files. What if one of them takes a LOT longer than the others. How do you keep track when they're all done?
jm
+1  A: 

I'm not familiar with MultipleDownload, but in case it doesn't meet your needs, the issue I take it is that you have a single object that is the delegate to many NSURLConnections, and you want to know how to keep them straight.

The delegate methods all return the NSURLConnection itself as their first parameter. So you can keep track of which data goes where by testing which NSURLConnection is calling you back. One way to do this is with an NSDictionary that maps the connection to its NSMutableData object. Now the trick is that you can't make an NSURLConnection be the key in a dictionary because it doesn't conform to NSCopying (and you wouldn't want it to). One way to work around this is to use the address of the connection such as:

NSString *key = [NSString stringWithFormat:@"%p", connection];

A better way would be to use NSValue with the valueWithNonretainedObject constructor. That way you can access the key object from the NSDictionary if you have to.

seano1
A: 

Is there any difference in using MultipleDownload class when trying downoad jpeg, pdf, ... or is it only for text?

rackom
ok i have found answer to my question ... but now when I am trying download large amount of data program "stuck". Not the program itself, but when I show allocation in Instruments It stops at about 7,5MB allocated space.
rackom
A: 

Hi,

is there any way to modify MultipleDownload to save data directly do file not to memory? I am using MultipleDownload library to download multiple (3+) larger files (30MB+) but when using it, it consumes lot of memory. Is it possible?

rackom