Asynchronous NSURLConnection call - objective-c

I am making a Asynchronous NSURLConnection call and downloading the data, how can I know when this thread is completed?
I am making this call from viewDidLoad, and obviously NSURLConnection is intuitively running in separate thread. So how would I know if the thread is completed and second wait until the thread gets completed to get the data pulled to the viewcontroller.

You will need to assign a delegate to the NSURLConnection that handles the processing and what-not of the data. Check out the documentation, it's pretty straightforward!

code speaks for itself
-(void) startRequest {
NSURLRequest* req = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://stackoverflow.com"]];
[[NSURLConnection alloc] initWithRequest:req delegate:self];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
}

Related

NSURLConnection problems

Hello my problem is that the delegates methods of my NSURLConnection are not being called, I read other post with the same problem but I can't fix this.
#implementation firstViewController
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[sendData sendValues];
});
end
other class
#interface SendInformation //this class extend NSObject<NSURLConnectionDataDelegate>
-(void)sendValues{
.......
NSURLConnection *conn = [[NSURLConnection alloc] init];
(void)[conn initWithRequest:request delegate:self];
}
end
The connection is working (I have all the delegate methods inside SendInformation.m) the problem is I never get a response, I read that you need to run the connection in the main thread, but if I do that, the interface will be freeze until the connection is done also I want the NSURLConnection in a different class.
Your code for creating the connection is strange. You want:
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
And of course self must implement all of the appropriate NSURLConnectionDelegate methods.

App not waiting for method to finish executing

I have a method getnamefornumbers which call a soap based web service(sudzc generated), which return a some data which i store in array to use.
But problem is that when i call the method it takes its time to execute and code after this method also executing, this result in null array.
what can i do so when this method completes its work then rest of the code executes.
You have to use custom delegates.You should define the protocol and delegate the current class to responsible for the class which performs getnamefornumbers. Once the operation done , you should return to caller class.
Here is the example of protocols http://mobiledevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
You should use the NSURLConnection delegation methods. In an async environment that's the normal behavior:
You make a call (in an async way)
The application keeps running (after you make the 1. call the program continues with the rest of the instructions)
So you have to two solutions, make it sync, so you will only continue after an answer comes (in your case the array is filled), which I would probably disencourage. Or, you make it async, and use the array when you actually have it.
As for specifics in how to implement this, more details must be provided, in order for me to advise you.
Update 1.0
-(void)requestConnectionToServer{
NSURL *url= [NSURL URLWithString:#"myWebServiceURL"];
NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:url];
self.reference=aReference;
[theRequest setHTTPMethod:#"GET"];
[theRequest setTimeoutInterval:20.0];
[NSURLConnection connectionWithRequest:theRequest delegate:self];
}
#pragma mark NSURLConnectionDelegate Implementation
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
NSLog(#"Response:%#",[[NSString alloc] initWithData:webData encoding:NSASCIIStringEncoding]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
NSLog(#"ERROR with theConenction %#",error);
}
Update 2.0
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
myArray = [MyWebServiceAccess getnamefornumbers];
dispatch_sync(dispatch_get_main_queue(), ^{
[myArray makeSomething];
});
});

How to handle different requests using connectionDidFinishLoading in the same delegate?

Whenever I do a curl call using the below code:
NSURL *url = [NSURL URLWithString:requestURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30];
if (connectionInProgress) {
[connectionInProgress cancel];
}
connectionInProgress = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
connectionDidFinishLoading is my final destination where I can manipulate the response data and call my next methods to continue with the app . If I hard-code some specific tasks like
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xmlData];
[parser setDelegate:self];
[parser parse];
[someLabel setText:parsedTextFromXMLData];
}
If I need to do another curl call to a different address, wouldn't someLabel setText always get re-set again? Is there a way to make this delegate function behave differently on each curl call? (btw, is connectionDidFinishLoading usually the right place to put the next step of codes?) If so then wouldn't it always get called again by the next curl call?
Have a look at this S.O. post for a recipe concerning NSURLConnection and multiple requests.The suggestion is doing something like this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == firstConnection) {
// do something
}
else if (connection == secondConnection) {
// do something else
}
}
EDIT: the idea here is that connectionDidFinishLoading is a method of your own delegate (so you write it). In the delegate, you store the address of each connection you create; then, when the connection comes back with the data, you tell which connection it is by comparing its address to the one you stored in the delegate. -END EDIT
Another option you have is using the ASIHTTPRequest framework, which offers a request-based (as opposed to connection-based) delegation mechanism, so each request has got a delegate object to handle the result; or, in other words, the delegate receives a reference to the request, so you can easily tell which request result you are handling.
ASIHTTPRequest offers a bunch of advantages over NSURLConnection. You can read about them in this S.O. post.
There're 2 options to do this:
you can implement a separate class, that will be responsible for handling NSURLConnection delegate stuff and create a separate instance for each request
you can use NSObject key-value methods on NSURLConnection instance for setting up some tag, that will be checked in connectionDidFinishLoading: method
For me, option 1 will be a better approach

Why release the NSURLConnection instance in this statement?

I read this in a book.
-(IBAction) updateTweets
{
tweetsView.text = #"";
[tweetsData release];
tweetsData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/public_timeline.xml" ];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
[activityIndicator startAnimating];
}
In this statement,is that correct to release the "connection" instance at that time? After releasing it which means this NSURLConnection instance will be destroyed since it's reference count is 0 ,how are we going to make this connection operation work after release this instance? THANKS.
I thought we should release it in one of the following callback methods,right?
connectionDidFinishLoading:
connection:didFailWithError:
It's actually fine to release it there, once the connection is sent out via initWithRequest, the only thing that matters is that the delegate exists or I believe the response will just be silently lost.
From what I can tell, the only reason to not release it there is if you want to call [connection cancel] at some point in one of the delegate functions, in which case it would be best to do what you suggest and release it in BOTH connectionDidFinishLoading and didFailWithError since only one of them will be called (right?).
Edit: For a more thorough answer, NSURLConnection initWithRequest is an asynchronous request. So it actually spawns it's own thread (but calls the delegate functions on the thread that called initWithRequest). So basically, on the thread that calls initWithRequest you are actually done with the connection object and you can release it. All the while it's doing stuff on some other thread that you don't need to be concerned with.
Also I should note that if you do release it there, make sure you DON'T release it in the finish/fail methods, because it won't be a valid object.

NSURLConnection leak?

i have set up a nsurl which grabs the data from http.
when i run instrument, it says i have a leak NSFNetwork object.
and how do i release theConnection in (void)ButtonClicked? or it will be release later on?
- (void)ButtonClicked {
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:KmlUrl]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:20.0f];
NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// receivedData is declared as a method instance elsewhere
NSMutableData *receivedData = [[NSMutableData data] retain];
[self setKMLdata:receivedData];
} else {
// inform the user that the download could not be made
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// append the new data to the receivedData
// receivedData is declared as a method instance elsewhere
[KMLdata appendData:data];
NSLog(#"didReceiveData");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// release the connection, and the data object
[connection release];
[KMLdata release];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[KMLdata release];
}
I finally found the answer for this.
The error in the above code (which by the way is the near-exact sample from the SDK docs) is not in the memory management code. Autorelease is one option, manual release is another. Regardless of how you handle your NSURLConnection object, you get leaks using NSURLConnection.
First up, here is the solution. Just copy these 3 lines of code directly into connectionDidFinishLoading, didFailWithError and anywhere else you release the NSURLConnection object.
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];
Credit to mpramodjain on http://forums.macrumors.com/showthread.php?t=573253 for the code.
The problem seems to be this – the SDK caches the requests and replies on the iPhone. Even it seems if your NSMutableURLRequest cachePolicy is set to not load the reply from the cache.
The silly thing is that it seems to cache a lot of data by default. I'm transmitting a lot of data (split into multiple connections) and started to get memory warnings, and finally my App died.
The docs we need are in NSURLCache (not NSURLConnection), they state:
NSURLCache implements the caching of
responses to URL load requests by
mapping NSURLRequest objects to
NSCachedURLResponse objects. It is a
composite of an in-memory and an
on-disk cache.
Methods are provided to manipulate the
sizes of each of these caches as well
as to control the path on disk to use
for persistent storage of cache data.
Those three lines have the effect of nuking the cache totally. After adding them to my App (GPS Log), my #living object count remains steady.
Hello have you test this delegate method ?
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
You can manage the cache more precisely.
"reset" NSURLCache *sharedCache can cause problems on other part of your code ?
This is a common question and is solved by the magic of [object autorelease]. In your code this would be as follows:
NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease];
In this way, the object is automatically added to the "autorelease pool" and dealloc'd at the start of the next run loop after it is no longer referenced.
Hope that helps
Edit: Also, I don't see why you're needing to call -retain on your receivedData variable.
I am using the static method/autoreleased approach and it appears to work fine:
[NSURLConnection connectionWithRequest:theRequest delegate:self];
This way you don't even have to worry about releasing in the delegate callbacks. It turns out that the retain count of the connection is actually 2 (not 1) after it is alloc'd in the examples above, which changes the way I thought about this memory "leak."
#rpetrich I actually don't think you need to worry about the delegate being released before the connection is released. The connection retains it's delegate and the connection itself is actually retained by some sort of open connections queue. I wrote a blog post on my experiments with NSURLConnection on my blog:
"Potential leak of object" with NSURLConnection