Before my view loads I call:
[theConnection cancel]; //assume theConnection is an NSURLConnection
I then proceed and make my proper NSURLConnection.
Will calling cancel before a connection is even made cause any problems?
No, the NSURLConnection documentation makes it clear that cancel is possible and that the delegate will receive no further messages once it is called. Also that the delegate is released on cancel.
Related
Today i faced a little problem, i wanted to know the reason of leak. Here is the code
[[NSURLConnection alloc] initWithRequest:request delegate:self];
This works fine no problem.
Now i was just wondering what happens to this allocated memory/object since no one is releasing it. So according to instinct i put autorelease while allocating like this:
[[[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
This threw me an error and crash "[NSURLConnectionInternalConnection _withConnectionDisconnectFromConnection]: message sent to deallocated instance"
Just wanted to know the concept and reason behind.
EDIT: I am not using ARC.
Thanks.
I think you can not use autorelease here for better memory management please release connection object in connection delegate method
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
{
[connection release];
}
So when your connection get finished It will release the connection object or you can release it ni viewDidUnload also
[NSURLConnectionInternalConnection _withConnectionDisconnectFromConnection]
this was called after the Autorelease Pool released your NSURLConnection connection object.
Best way should be, have a reference for the variable and release it, once you are done fetching the data. (May be in the viewDidUnload: ?)
You can use this method for better memory management
NSURLConnection *connection=[NSURLConnection connectionWithRequest:urlRequest delegate:self];
Above connectionWithRequest method is class method and manage memory itself you don't need to release it.
As far as I know after allocating the connection object objc runtime adds the object to autoreleasepool then other delegate method sent to deallocated instances.
I am writing location based app, get weather information through API by using NSURLConnection for current/other places .At first time I sent request its working successfully. But next time I want to refer the information for same place it not working while NSURLConnection is not call the any delegate methods.
this is my code:
NSString *strs=[#"http://www.earthtools.org/timezone-1.1/" stringByAppendingString:[NSString stringWithFormat:#"%#/%#",place.latitude,place.longitude]];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:strs]];
self.reqTimeZone=[NSURLConnection connectionWithRequest:request delegate:self];
[self.reqTimeZone start];
I assume you mean NSURLConnection (NSConnection doesn't exist). NSURLConnection can only be used once. See Reusing an instance of NSURLConnection.
Another gotcha with NSURLConnection is that it must be ran on a thread with a runloop. The main thread automatically has a run loop, but methods called on GCD and NSOperation threads need to have the runloop created explicitly. In practice you probably don't need to run NSURLConnection on a background thread. The download operation will not block the main thread. If you do decide to run NSURLConnection on a run loop the easiest way to do it is probably to create an NSOperation subclass and create the run loop inside of -main.
Where is the right place to cancel an ongoing request of ASIHttpRequest? This is how I do my cancellation but it keep on crashing when I transfer from one viewcontroller to another without letting the request to finish. The cancellation fo request works fine, but when switch back to the first Viewcontroller it will crash.
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if(!DID_FINISH_REQUEST)
{
[requestNewReleases setDelegate:nil];
[requestNewReleases cancel];
[requestNewReleases clearDelegatesAndCancel];
}
}
In the ASIHttpRequest documentation there is an example of a request being cancelled in the dealloc method:
Safely handling the delegate being deallocated before the request has
finished
Requests don’t retain their delegates, so if there’s a chance your
delegate may be deallocated while your request is running, it is vital
that you clear the request’s delegate properties. In most
circumstances, if your delegate is going to be deallocated, you
probably also want to cancel request, since you no longer care about
the request’s status.
In the example below, our controller has an ASIHTTPRequest stored in a
retained instance variable. We call the clearDelegatesAndCancel method
in it’s dealloc implementation, just before we release our reference
to the request:
- (void)dealloc
{
[request clearDelegatesAndCancel];
[request release];
...
[super dealloc];
}
It depends on your architecture and application needs - eg. If there are multiple http requests only some of which need to cancel?
Then solution -
for (ASIHTTPRequest *req in ASIHTTPRequest.sharedQueue.operations)
{
[req cancel];
[req setDelegate:nil];
}
This will cancel and remove the delegate of all in progress requests that have been assigned to the default queue.
I am running a NSURLConnection on a separate thread (I am aware that it is asynchronous and works when running on the main thread), but it is not making delegate calls even when I pass the parent thread as the delegate. Does anyone know how to do this?
Code:
-(void)startConnectionWithUrlPath:(NSString*)URLpath {
//initiates the download connection - setup
NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[myURL release];
//initiates the download connection on a seperate thread
[NSThread detachNewThreadSelector:#selector(startDownloading:) toTarget:self withObject:self];
}
-(void)startDownloading:(id)parentThread {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[NSURLConnection connectionWithRequest:myURLRequest delegate:parentThread];
//The delegate methods are setup in the rest of the class but they are never getting called...
[pool drain];
}
EDIT*
The reason I need to run NSURLConnection on a separate thread is because I am downloading something in my iPhone app and the download cancels when the user locks the screen (it continues fine if the user simply presses the home button and the app goes into the background). I understand this is due to my running the connection asynchronously on the main thread and not a separate one.
I have also tried this code (NOT in a separate thread) when initiating the NSURLConnection:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:myURLRequest delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
[connection release];
But it I have the same problem with this regarding the download being cancelled on screen lock.
*UPDATE
To add to Thomas' answer below (Please note that James Webster's answer is also correct regarding the exiting of a thread) the Apple docs explain:
"Suspended state - The app is in the background but is not executing code. The system moves apps to this state automatically and does not notify them before doing so. While suspended, an app remains in memory but does not execute any code."
Since when the screen is locked by the user the app is put into the background state and than right away into the suspended state, all execution is stopped killing any downloads and no warning that this is about to happen is given... there may be a notification which tells me that the user has locked the screen but I haven't found one yet.
I therefore pause (save certain information and cancel the NSURLConnection) all downloads when the app goes into the background and resume it with the HTTP Range header when it gets active again.
This is a workaround which is ok but not ideal since the download is not occurring in the background which affects the user experience negatively... bummer.
Since your NSURLConnection is asynchronous, the end of your -startDownloading method is reached immediately, and the thread exits.
You should indeed schedule your connection on the main runloop (or use GCD).
The device lock is another issue. When the device is locked, your application is suspended to save battery life. You can probably ask for an extra amount of time when suspending in order to finish your download.
I think your problem might be that the NSURLConnection has been deallocated as soon as you exit the startDownloading: message (or more accurately when your autorelease pool is drained)
However I think your methodology might be a bit uncouth anyway. NSURLConnection the way you are using it is asynchronous and will appear to be threaded anyway.
Try this and see if it works as you expect it to (i.e. your app doesn't pause while your connection is busy)
-(void)startConnectionWithUrlPath:(NSString*)URLpath {
//initiates the download connection - setup
NSURL *myURL = [[NSURL alloc] initWithString:URLpath];
myURLRequest = [NSMutableURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60];
[myURL release];
[NSURLConnection connectionWithRequest:myURLRequest delegate:self];
}
I want to show activity indicator while sending and receiving synchronous asihttprequest from server. I have used activity indicator as the asihttprequest is send but it did not showing in iPhone due to synchronous request.Any suggestion how to show activity indicator during synchronous data transfer.Thanks
Synchronous request calls your activity indicator delegate method setProgress: on the main thread.
B/c you are using ASIHTTPRequest on the main thread you are blocking the UI, hence calls to setProgress: are queuing to be dispatched after the request is finished, but by that time the progress is already 100%
To solve this use either asynchronous request or call synchronous request on a background thread using
[self performSelectorInBackground:#selector(startSynchronous:) withObject:nil];
Edit
Remember to create your own autorelease pool to handle the memory inside your startSynchronous: method
-(void)startSynchronous:(BOOL)animate{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *autoreleasedString = #"xxx";
NSLog(#"%#",autoreleasedString);
[pool drain];
}