Downloading multiple files in iphone app(Objective c) - iphone

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,

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....

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.

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.

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.

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];

Related

NSOperation and NSURLConnection conflicts

What is the best way to run code on a separate thread?
NSInvocationOperation *operationToComplete = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(operationMethod) object:nil];
NSOperationQueue *queueToStart=[[NSOperationQueue alloc] init];
[queueToStart addOperation:operationToComplete];
-(void) operationMethod
{
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&_response error:&_error];
}
OR:
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
I've been doing the second way but am little bit confuse regarding this or use another way to do this.
Using operation queues with synchronous requests can be especially useful if you have many concurrent requests that you want to invoke. Operation queues make it easy to not only specify concurrent operation, but also to specify maxConcurrentOperationCount to constrain how many concurrent operations you want to run (which is important if you're firing off a whole bunch of them as you're limited to how many can operate concurrently with a given server).
Your latter example, with initWithRequest, is useful if you need the NSURLConnectionDataDelegate methods (for any of a number of reasons, e.g. you want to update progress view, you want to perform some streaming operations, you want to be able to cancel connection, etc.).
A third approach is to marry the initWithRequest approach with an NSOperationQueue, namely to wrap the NSURLConnection in its own NSOperation. This marries these two techniques, providing the richness of NSURLConnectionDataDelegate methods (cancelable, progress updates, etc.), with the power of operation queues (the ability to add network requests to queue for which you can configure degree of concurrency, establish dependencies between operations, etc.), but providing a nice interface. There are some idiosyncrasies to properly implement this approach (you have to schedule/create a runloop for NSURLConnection if you use it in an NSOperationQueue). I might, therefore, advise using a third party library, such as AFNetworking, if you want to enjoy the richness of this technique without getting lost in the implementation details.
In answer to your question of "which is best", it just depends upon what you're trying to do, as they all have pros and cons. But I prefer a NSOperation-based NSURLConnection, and would generally advise using AFNetworking if you want to simplify your development effort.
By the way, you can probably simplify the first example:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&_response error:&_error];
}];
Using Grand Central Dispatch (GCD) you can run code in background, which one is easier also.
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
And also NSURLConnection supports two modes of operation: asynchronous and synchronous. Neither uses separate threads at all.

Variable released prematurely during asynchronous request

My memory-management and threading knowledge is very limited, so I may be missing something really basic. I've found a work-around for this problem, but it really, really bothers me that I can't see what's happening.
I have a class that makes two asynchronous HTTP requests, one for an XML configuration file and another for an image. Because there are two asynchronous requests going on in the same class, I'm reusing the same NSURLConnectionDelegate methods (maybe factor). I first asynchronously fetch the configuration file and extract two urls, stored as sponsorImage and sponsorUrl. Then I use the value of sponsorImage to asynchronously fetch image data. I've found, though, that after I've got my image (after the second asynchronous event has completed), sponsorUrl has been released.
I accidentally found that I can prevent sponsorUrl from getting released if I "do something to it" in the method where the image request is created -- and by "do something", I mean just that. Basically, my code looks like this:
- (void) loadImage
{
sponsorUrl = [sponsorUrl stringByAppendingString:#""];
NSURL *url = [NSURL URLWithString:sponsorImage];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:dateString forHTTPHeaderField:#"If-Modified-Since"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection start];
[connection release];
}
If I remove the first line of this method (where I'm adding "" to the url), the variable is retained. If I remove it, it gets released. This makes no sense to me at all.
I've tried declaring sponsorUrl with #propterty (nonatomic, retain); I've tried declaring sponsorUrl statically; I've tried adding [sponsorUrl retain] where I set it, but it doesn't make a difference. The only thing that works is "touching" the variable before making the second request.
What am I missing?
As your are using a convenience constructor the variable is autoreleased! Only if you are using methods like alloc, copy or new they are retained implicitly.
Secondly, by writing sponsorUrl = .... your are not using the generated setter but the generated instance variable. You will need to write self.sponsorUrl = #"Blah"; or [self setSponsorUrl:#"blah"] in order to have the setter retain the variable.
Indeed, it seems you have some issues with memory management.
It is pretty difficult to explain what is happening because you are not providing the full code that uses your variables. Just as an example, take the statement:
sponsorUrl = [sponsorUrl stringByAppendingString:#""];
what you do is assigning to sponsorURL a new value; the old value (the one you initialized the variable with in the first place, i.e., the one that got the retain you mention) is released (stringByAppendingString forges a new object); the new object that sponsorURL points to is an autoreleased object whose lifetime is not exactly known: we only know that at some point it will be freed (possibly at the next main loop iteration). So, by "touching" the variable, you are assigning a new value to it which has a lifetime starting with the point where you touch the variable... pretty unreliable, in any case.
My suggestion is the following:
define two properties in your class to handle sponsorURL and sponsorImage;
make them of the retain kind;
assign value to them only through their accessor methods, i.e, self.sponsorURL = [...]
make sure that any objects you assign to the properties are autoreleased objects (or else, do a release with the assignment).
If you provide more code, then it would be possible to review it more thoroughly, but if you follow the guidelines above, you will have no problems at all (approx...)

iPhone NSURLConnection initialization problem

What is difference between this two lines, they are in different apps but first one seems to work and I have problems with the second one; and which one should i choose over another? my app will constantly receive and send back data with a webservice.
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
NSURLConnection *theConnection = [NSURLConnection connectionWithRequest:request delegate:self];
And where should I release the connection object, after every didFinishLoading? but then doesn't it take much time on every request to connect?
The first one is an instance of NSURLConnection where you take ownership of the object, so you have the responsibility and hence must release it. Details on ownership reference.
The second one is an auto-released object so you dont need to release it. It will be released automatically when the auto-release pool is drained.
The second creates an auto-released connection, so if you don't explicitly retain it, it will disappear and your application will probably crash.
You can use either, you just need to understand objective-c memory management on the iPhone.
There is, as ever, a good explanation on the Apple site, it really is worth reading and understanding as once the penny drops, you'll never make the same mistake again.
with first line you create an object with init method , which make you the owner of the object , so you must release it . The second line you use a convenient constructor, which does not make you owner of that object.in this case, if you want to manipulate with life-cycle of that object you must send another message to retain it : NSURLConnection *theConnection = [[NSURLConnection connectionWithRequest:request delegate:self] retain], and the count of object will be 2 .. even if in the second line your object automatically receive a autorelease message , the count after that will be 1 .. so if you retain object you must release it ...
you asked : And where should I release the connection object ? i think in method called connectionDidFinishLoading:connection or in the method connection:didFailWithError:

Another Delegate for ASIHTTPRequest Asynchronous?

How can I create a new file containing just it's own delegate so that I can make an ASIHTTPRequest with its own asynchronous ending, and something easy enough where I just need to set [request setDelegate:self]; to something like [request setDelegate:AlternateDelegate]; and just add an include at the begining of the document to reference the AlternateDelegate delegate
I know this question is old, but in case anyone comes across it:
#Hankweb seemes to be talking about using a request as its own delegate. There are certainly situations where this works. For example, I'm working on a project that uses ASIHTTPRequest to fetch JSON from a remote source and import it into a Core Data store.
This operation (literally, as ASIHTTPRequest is a subclass of NSOperation) is almost entirely self-contained; I have a custom request on a background thread using a streaming JSON parser to import objects into a NSManagedObjectContext, which, when saved, triggers a notification that I catch internally and pass to the main thread's context using performSelectorOnMainThread:waitUntilDone:.
I'm using ASIHTTPRequest's block support to accomplish this; in my custom initWithURL: method, I set up the relevant callbacks (dataReceivedBlock, completionBlock, failureBlock, etc.). The traditional delegation pattern (using the ASIHTTPRequestDelegate protocol) should also work, though.
One gotcha: you should make sure the request doesn't retain itself too many times, or else you'll end up with a memory leak. This can be easy to miss when using multiple threads, and especially when using blocks. Instead of:
- (id)initWithURL:(NSURL *aURL) {
//...
[self setCompletionBlock:^{
[self doSomething];
}];
//...
return self;
}
Use the __weak attribute (or __block if you're not using ARC) when referencing self within the blocks:
- (id)initWithURL:(NSURL *aURL) {
//...
__weak id blockSelf = self;
[self setCompletionBlock:^{
[blockSelf doSomething];
}];
//...
return self;
}
If you don't know why this is important, make sure to read Apple's guide to blocks in Objective-C, and the ASIHTTPRequest block API documentation.
A delegate for ASIHTTPRequest is just a standard objective C object. Just create a new class, include it's header, create/get the object and set the delegate to be that object.
Have you tried this and run into a problem? If so what is the problem?

Best approach for XML parsing on the iPhone

I've familiarized myself with the NSXMLParser from the iPhone SDK but I find the event-driven nature of it awkward for my purposes. I just want to extract some element values but this concept of having to handle the startElement, foundCharacters, and endElement seems like more work than it really should be. Am I just looking at this the wrong way or is there a simpler tree/DOM-based way of working with XML in the iPhone SDK?
If the advice is to just work with NSXMLParser, are there certain design patterns I can use to keep my code from having 5 levels of nested ifs in the startElement method?
If you're on the iPhone, using tree-based parsing can be a prohibitive memory hog. Trust me, I've been there, and I've tried many different approaches over the last five months of development of my main iPhone application. Tree-based parsing works fine until you download someone's comment stream containing 400 very long comments, clocking in at about 600KB of raw data. Quite aside from the size of the resultant XML tree, the memory allocated internally while creating that tree can be enormous.
I wound up creating a variant of NSXMLParser which pulls data in from a supplied NSInputStream rather than using a single chunk of data, and which passes only 1KB at a time into libxml for handling (NSXMLParser uses libxml too, but passes 100% of the data in one go).
The source code is available on github (look in the StreamingXMLParser folder). You'll also find a delegate superclass in there; for most parsing needs you can subclass AQXMLParserDelegate and implement -start[Element]WithAttributes: (NSDictionary *) attrs and -end[Element] in your subclass. These methods will be called for you as start & end tags are discovered, and inside the end tag you can use self.characters to access the content characters or CDATA of the element.
For more on the relative memory footprints of the different parsers (albeit on the Mac, not the iPhone) see my original blog post here and the followup on NSXMLDocument here.
Consider the following code snippet, that uses libxml2, Matt Gallagher's libxml2 wrappers and Ben Copsey's ASIHTTPRequest to parse an XML document.
The nodes instance of type NSArray* will contain NSDictionary* objects that you can parse recursively to get the data you want.
Or, if you know the scheme of your XML document, you can write an XPath query to get you to a nodeContent or nodeAttribute value directly.
ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com/"];
[request start];
NSError *error = [request error];
if (!error) {
NSData *response = [request responseData];
NSLog(#"Root node: %#", [[self query:#"//" withResponse:response] description]);
}
else
#throw [NSException exceptionWithName:#"kHTTPRequestFailed" reason:#"Request failed!" userInfo:nil];
[request release];
...
- (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData {
NSArray *nodes = PerformXMLXPathQuery(respData, xpathQuery);
if (nodes != nil)
return nodes;
return nil;
}
Repurposing the code from Seismic XML provides a very good API that creates NSObject subclasses from XML.
If the advice is to just work with NSXMLParser, are there certain design patterns I can use to keep my code from having 5 levels of nested ifs in the startElement method?
I depends on what you are trying to do. You could put your element names in a dictionary and take action based on the relevant object in a dictionary - this is effectively what SeismicXML does.