NSURLConnection start + autorelease - iphone

In my app I have to make a HTTP call and I am not interested in the response result from the web service. So I was wondering if it is OK to create a connection and start it and autorelease it not to cause a memory leak.
NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:nil];
[connection start];
[connection autorelease];
Is it possible that the garbage collection could destroy the connection object before the HTTP call is made?

This is a good question. Even if it is not stated explicitly that the NSURLConnection is retained by the operating system, it appears obvious that the connection request is added as a source of the run loop and then, as such, retained.
In any case it should be better for you to set a minimum delegate for the request by just observing the connection termination with connectionDidFinishLoading: and after that release your connection object, as written in this part of the documentation:
Finally, if the connection succeeds in downloading the request, the delegate receives the connectionDidFinishLoading: message. The delegate will receive no further messages for the connection and the NSURLConnection object can be released.
For the same reason you should observe the end of connection due to an error with connection:didFailWithError:.

It is understandable that you don't require the response from the server. But don't you want to ensure that a connection was established? What if the connection times out? The client will not even get to know about the error. I feel it is better that you release the connection instance after you have confirmed the the request reached the server.
Also, calling start in your case is not required, as you are not using initWithRequest:delegate:startImmediately: method with NO for the startImmediately parameter.

Related

How to tell iPhone NSURLConnection to abort

I have an app that makes moderate use of NSURLConnection. These async calls eventually finish and release properly (it looks like), but sometimes it takes some time for them to finish.
So, there are times when I exit the app, (note, not just sending it the background), that some of these connections are still active. If I immediately restart the app, the app freezes on startup. (didFinishLaunchingWithOptions never seems to get called).
While I'm not certain these connections are the issue, it would probably be good to terminate or cancel any remaining. Any suggestions on how to do this?
Bonus points on how to debug the restart also. (I'm already saving NSLog statements to a downloadable file)
You can cancel any NSURLConnection by sending it a cancel command.
[connection cancel];
From Apple docs
Cancels an asynchronous load of a
request. Once this method is called,
the receiver’s delegate will no longer
receive any messages for this
NSURLConnection.
Your start up issue could be related but hard to tell without knowing what type of data you're downloading and how you are using it.
Make sure you are calling release on the connection. Maybe it doesn't call shutdown or close on the socket until the last reference is dropped. I do something like this with no issues with references.
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
For cancel last request : [NSURLConnection cancelPreviousPerformRequestsWithTarget:self];
For cancel any specific request : [request cancel];
Note: Here request is the instance of NSURLConnection

Reusing an instance of NSURLConnection

I'm using an instance of NSURLConnection on the iPhone to request data from a server, managed by a delegate as usual. The requests are quite frequent (maybe once every 2 minutes say) and have a common and fixed URL. Rather than seeing the good instance of NSURLConnection being released after each download and then a new one being created:
Is there any worth in retaining the first connection and reusing it? (I'd hope so, one good authentication should be worth a thousand.)
If so, how do I reuse it? The standout method in the docs is -start but this seems to crash the app when called on an already used (and non-nil) instance of NSURLConnection. [The docs do say -start "causes the receiver to begin loading data, if it has not already."]
In case it's of help with regard to the above questions, I am (was!) proposing:
if (connection_ == nil)
{
connection_ = [NSURLConnection connectionWithRequest:request
delegate:self];
}
else
{
[connection_ start];
}
The docs seems to say that the URL connection retains it's delegate (unconventional, but necessary in this case) and then releases it when the connection finishes loading, fails or is cancelled.
The problem is that the delegate isn't a settable property on NSURLConnection and so you can't reset it after it's been released. This pretty much renders the URL connection useless after it has run once, requiring you to release and recreate it if you want to do it again.

NSURLConnection and keep-alive

I have a small bug in my client app that uses NSURLConnection. I have tracked it down to an unexpected connection keep-alive that seems to confuse the web server (probably a bug on the server side). The workaround would be to force-close all outstanding connections at a certain point. Can I do this somehow with NSURLConnection, i.e. something like
[NSURLConnection closeAllIdleConnections];
ASIHTTPRequest has an expirePersistentConnections method. It may do what you're looking for.
It's not a drop-in replacement for NSURLConnection, but it's not too hard to port code from NSURLConnection to ASIHTTPRequest.
I think you might want to look at the following method defined for NSURLConnections. This assumes that you made the call asynchronously. If it isn't an async call, then it probably should be.
cancel Cancels an asynchronous load of
a request.
(void)cancel
Discussion Once this method is called,
the receiver’s delegate will no longer
receive any messages for this
NSURLConnection.
Hope this helps. Andrew.

iphone: applicationWillTerminate not called during a NSURLRequest?

I am working on an application where the user at some point must wait for a proper response from a webservice. This might take some time, because it requires a manual confirmation from the webservice. Because of this, the timeoutInterval on the request is set very high to prevent it from terminating too early.
The problem comes when starting the application immediately after the program has returned to the home screen. The application will not start (black screen), and I think it is because the request hasn't been released and is still waiting for a response (I might be wrong though).
I tried the applicationWillTerminate method, but it isn't called when pressing the home button. Again, this might be because the application is still waiting for a response, but a better explanation would be greatly appreciated :)
Also, does someone have any idea on what to do?
code:
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:urlAdress]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10000];
NSHTTPURLResponse* response = nil;
NSError* error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:theRequest
returningResponse:&response
error:&error];
Making a synchronous request on the main thread will block the entire run loop until you receive a response or the request times out. Nothing will get called during this time, including applicationWillTerminate. It is a very bad idea to do this. You should either detach a separate thread for the request or create an asynchronous NSURLConnection.
That being said, the OS will free all memory anyway when it terminates your app so there is little chance that anything from the last launch will be "left over" upon relaunch. Unless your server is blocked because it lost its client when your app terminated. In which case you have to write your server in a way that can handle such a case because it can happen anytime.
If the applicationWillTerminate delegate method is not called,
Then I guess the following delegate method would be getting called.
- (void)applicationWillResignActive:(UIApplication *)application
{
NSLog(#"Application Did Resign Active");
}

Making GET and POST Requests from an iPhone Application - Clarification Needed

I'm following along with this useful looking answer to my question.
It seems to be working, but here are two questions I have:
How do I detect an HTTP error? The didFailWithError method doesn't seem to be getting called?
UPDATE: It considers any response a success. So I guess I have to handle HTTP errors in the didRecieveResponse method, but besides telling the user there was an error when I hit an HTTP error, do I need stop the connection somehow? And/or cleanup?
I see this line in the answer:
[[NSURLConnection alloc] initWithRequest:request delegate:self];
Do I need to release that? Where, how, when?
You will get the status code returned in the didReceiveResponse
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSHTTPURLResponse *httpResponse;
httpResponse = (NSHTTPURLResponse *)response;
int statusCode = [httpResponse statusCode];
//statusCode will be the http code returned like 201,500
}
For stopping the connection, use a class-level variable for the connection. The best way to go about it would be create a wrapper which sends requests and receives response. Make your viewcontroller a delegate of this class and whenever the didReceiveResponse gives an error status code, call the appropriate method of the delegate and stop the connection.
Here's a good wrapper class example
http://kosmaczewski.net/projects/objective-c-rest-client/
Yes, you need to release that object. See the Memory Management Programming Guide for Cocoa. Basically, if you ever create an object with a method name that begins with alloc or new or contains copy, you become an owner of the object and are responsible for freeing it later. Only in the case where you know you're going to need the object up until program termination is it ok not to free it, in which case the operating system reclaims the memory when your app terminates.
If you only need the object within a small scope, you can send it the autorelease message. This will add it to the autorelease pool. The autorelease pool periodically sends a release message to each object in it. It's kind of complicated; see the section on autorelease pools. For example:
In this case, though, because NSURLConnections are asynchronous, autoreleasing won't work. You don't know exactly when it's going to call back into your object with data, so you want to make sure the object hasn't been released yet. The only way to be sure is to know exactly when you're done with the object, and then send it a release message yourself.
All of the various init* functions return a pointer to the given object, so you can just do:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
...
// when done with connection:
[connection release];
Answering the question in your "update"...
Immediately autorelease the NSURLConnection. The connection object is retained by the NSRunLoop (to which it adds itself automatically unless you use the startImmediately:NO constructor). It will get automatically removed from run loop (and hence dealloc'd) on error or finish.