I am intending to create 2 requests using NSURLConnection. When the server responds and calls connectionDidFinishLoading it passes in the connection as the parameter, but how do I identify which connection is passed in?
Save both NSURLConnection objects as member variables of whatever delegate object you passed to connectionWithRequest:delegate:. Then you can just compare each of those to the NSURLConnection passed to connectionDidFinishLoading:, and respond appropriately:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == firstConnection) {
// do something
}
else if (connection == secondConnection) {
// do something else
}
}
Another slightly more object-oriented option would be to create two different delegate objects, each of which knows how to deal with each each type of connection. Then just pass the appropriate delegate when you create each connection. That way you don't need to check to see which connection you have, because each delegate will only receive connectionDidFinishLoading: for its own connection.
I prefer different delegates for each connection, too. Although it's a bit of overhead. Fortunately, you can simplify things by using blocks. It's a new feature that doesn't exist in standard SDK yet, but there is 3rd-party framework called PLBlocks that you can use already. Here is an article on how to use them, it also contains example for NSURLConnection.
This is the client code making HTTP request with block callback:
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]];
[NSURLConnection sendAsynchronousRequest:req onCompletionDo: ^(NSData *data, NSURLResponse *res, NSError *err) {
NSLog(#"data: %ld bytes. res: %#, error: %#", (long)[data length], res, err);
[cell.activity stopAnimating];
}];
I used to create a custom wrapper around NSURLConnection, too, but I've now switched over to ASIHTTPRequest. This is a fantastic library providing much more flexibility and features than NSURLConnection. Have a look and give it a try, it's really worth it.
What I do in my projects is create a wrapper class for the connection. This way, you can keep a new instance for each connection you need, and maintain these classes in another manager class.
Something like [AsynchronousConnection initWithURL:delegate:selector:]
Then you can be ensure the right thing is called when the NSURLConnection is done/failed.
Please do not refer https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSURLConnection_Class/Reference/Reference.html
GO to the NSURLConnection.h file and you will find the following.
When created, an NSURLConnection performs a deep-copy of the
NSURLRequest. This copy is available through the -originalRequest
method. As the connection performs the load, this request may change
as a result of protocol canonicalization or due to following
redirects. -currentRequest can be used to retrieve this value.
Ultimately [connection currentRequest].URL absoluteURL might help.
Regards,
PRASANNA.
Related
I know that the pattern in iPhone is to use ASync connection calls (using the informal protocols that is implemented by the current class).
In my case, I've created a utility class to do the networking staff and then return the data to the ViewController.
I find is inadequate to implement the connection model as Async in a utility class because r I will write a block of code in the ViewControlle such following: (which IMHO is bad)
MyUtilityConnection* utilConn = ....
while (true)
{
if ([utilConn checkUnderlyingAsyncConnectionFinishedLoading]) break;
}
NSData* dataFromUrl = [utilConn dataFromUnderlayingConn];
So, the question is, Does using Sync connection model in iPhone could causes problem? and solutions?
(What about the drawing will stril hanging until the data come???)
AVOID by all means to do synchronous connections! This will obviously freeze your UI (and it gets worse if you don't have a good bandwidth of course).
What you could do is to use the blocks syntax to write more readable code when you need to download data. Create a class that implements the NSURLConnection delegate methods, and then call the block when the data is done.
See my OHURLLoader class on github for example that does exactly that (and that's only one solution).
Usage example:
NSURL* url = ...
NSURLRequest* req = [NSURLRequest requestWithURL:url];
OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req];
[loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) {
NSLog(#"Download of %# done (statusCode:%d)",url,statusCode);
outputTextView.text = loader.receivedString;
} errorHandler:^(NSError *error) {
NSLog(#"Error while downloading %#: %#",url,error);
outputTextView.text = [error localizedDescription];
}];
During sync methods (sendSynchronousRequest:returningResponse:error:) the UI is non-responsive (assuming that the sync method is called on the main thread).
But they are fine on background threads, the easiest way to accomplish sync calls on a background thread is with GCD.
I have a library project that uses ASIHTTPRequest to make URL requests and parse the responses. The library will be used by a separate iPhone app project.
If my iPhone controller code responds to a touch event, then calls into the library to make URL requests, how do I best perform the requests asynchronously?
In the library, if I use the delegate pattern for asynchronous requests as shown in the ASIHTTPRequest sample code, how do I return data from the library back to the calling code in the iPhone controller?
If I instead make synchronous URL requests with ASIHTTPRequest inside the library, what's the easiest way to put the calls to the library from the iPhone controller on a separate thread to avoid tying up the UI thread?
I'm no ASIHTTPRequest expert (NSURLRequest has always done me fine), but from a quick poke at the code, it looks like you'd use its delegate and didFinishSelector properties to give it someone to tell when the URL request is finished. So, for example:
- (void)startURLRequest
{
ASIHTTPRequest *myRequest;
/* code to set the request up with your target URL, etc here */
myRequest.delegate = self;
myRequest.didFinishSelector = #selector(HTTPRequestDidFinish:);
/* ... */
[myRequest startAsynchronous];
}
- (void)HTTPRequestDidFinish:(ASIHTTPRequest *)request
{
NSLog(#"Request %# did finish, got data: %#", request, request.data);
[myTargetForData didReceiveData:request.data fromURL:request.originalURL];
}
Apple explicitly recommend that you use the built-in runloop style mechanisms for asynchronous HTTP fetching, not separate threads. Using separate threads is likely to result in worse performance — at least in terms of battery life and/or device heat, even if it's still fast enough.
That said, as a learning point, by far the quickest way to switch something onto a separate thread and have it report back to the main thread (remember: UIKit objects may be messaged only from the main thread) is by changing this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* lots of expensive processing here, and then... */
[self postResult:result];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self doExpensiveOperationOn:#"some value or another"];
}
Into this:
- (void)postResult:(NSString *)result
{
instanceOfUILabel.text = result;
}
- (void)doExpensiveOperationOn:(NSString *)source
{
/* we're on a thread without an autorelease pool now, probably we'll want one */
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
/* lots of expensive processing here, and then... */
/* in this simplified example, we assume that ownership of 'result' is here on this thread, possibly on the autorelease pool, so wait until postResult has definitely finished before doing anything that might release result */
[self performSelectorOnMainThread:#selector(postResult:) withObject:result waitUntilDone:YES];
[pool release];
}
- (IBAction)userWantsOperationDone:(id)sender
{
[self performSelectorOnBackgroundThread:#selector(doExpensiveOperationOn:) withObject:#"some value or another"];
}
There's about a million possible concurrency errors you can make by just going threaded without thinking about it though, and in that example an obvious problem is that whatever triggered the IBAction can [probably] trigger it several more times before doExpensiveOperationOn has finished. Multithreading is not something to be dashed into lightly.
For anyone's future reference, the easiest approach I found is to use the async request functionality built into ASIHTTPRequest, setting my library object as the delegate and setting the didFinishSelector: and didFailSelector: values to different methods inside my library for each request.
At the end of processing each response, I assign the parsed response (an NSString* or NSArray*) to a property of my library object instead of returning a value.
When my iOS view controller delegate is loaded, I add a change observer to each of the properties in the library using Key-Value Observing. When the response is parsed and assigned to the property in the library, the observeValueForKeyPath:ofObject:change:context: method is called in the code of my view controller delegate, and from there I can figure out which property was changed and therefore what UI needs to be updated.
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?
i have a [self parseXMLFileAtURL:path] method. is there anyway of stopping it midway? like terminating the method.
Reason for doing is because im running an apache http server on one pc and if the server is not running, the app will 'hang' if this method is called. so i want to to something like terminating the method after a certain amount of seconds , 5s maybe. and display an alert message.
I'd have two suggestions... one, if you possibly can, use NSMutableURLRequest with NSURLConnection to retrieve the data; which gives you much better control over things like timeout.
NSError * error;
NSURLResponse * response;
NSMutableURLRequest * request = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:#"http://..."]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:60.0];
// Not sure if you need this, but I frequently do POSTs as well, so whatever:
[request setHTTPMethod:#"GET"];
NSData * responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
NSString * xml = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
(NB: You'll have to check the error response, I just omitted it for clarity)
Also, ideally (since in my example I use the synchronous method) this should be run on a background thread... but I found it much easier to run this on the background thread manually using "performSelectorInBackground:" and use the synchronous methods, than I did using the async methods. Keep in mind, you'll have to create your own auto release pool if you do that... but that's two lines, and it's super easy.
Short of that, it IS possible to terminate the method... you'd have to run it on a different thread, and kill the thread if it took too long... but really, the NSMutableURLRequest isn't so bad, and it already gives you the timeout options you're looking for.
The thread programming guide at: http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html#//apple_ref/doc/uid/10000057i-CH15-SW2 talks about killing threads... and tells you (indirectly) how to do it... but if you simply kill the thread, you are almost guaranteed to leak something.
I'm pretty sure that you could try installing a signal handler with sigaction to handle SIGALRM and use the alarm function. There is, however, probably a better solution using the Cocoa framework. I'll leave this here, but it's probably not the easiest way.
A method is just a C(++) function, so there really no way to stop it.
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.