1
votes

I am aware of discussions regarding nsurlconnection on ios, and that there is a minimum of 240 seconds for a timeout. My question is, if I am sending a synchronous call via NSURLConnection's + (NSData *)sendSynchronousRequest:(NSURLRequest )request returningResponse:(NSURLResponse *)response error:(NSError **)error, is there any chance I can cancel this before the 240 seconds is up? I am thinking perhaps setting a timer to cancel this synchronous request, but im not even sure if its even possible? Im thinking:

[self performSelector:@selector(cancelRequest:) withObject:myRequest afterDelay:myTimeOut];

I have a feeling this will result in disaster if somehow the request has been released, and I would have no way to determine that. Thoughts? Has anyone tried to do this? This is a synchronous call.

3
For anyone looking here for a solution, I have a tentative one. Here is what you can do: Create a timer and make SURE you schedule it for NSRunLoopModeCommon. Then create your NSURLConnection and schedule it in the above run loop mode. When either the connection returns or timer fires, set a flag. Your busy loop should catch this and exit. Note that at least one thread will be busy spinning during this process, so you have to make sure that thread is NOT the main thread. I will post a code sample when I have more time. Scheduling the run loops is VERY IMPORTANT for this to work! - Ying
This cannot work. First, you cannot schedule a synchronous request for any run loop, you can only do that with asynchronous requests; synchronous requests simply block whatever thread makes the call--and it is a class method, not an instance method. Second, NSURLRequest does not even respond to anything like cancelRequest:. You cannot send any kind of cancel message to an NSURLRequest, your app will just crash. - Jason Coco
hmm, its not cancelling an NSURLRequest though-maybe I should make that more explicit. It's cancelling an NSURLConnection. I am not saying the connection should be synchronous, only that it appears syncrhonous from the point of the caller. This means making an asynchronous request, blocking the thread, and cancelling from another thread. Is this still impossible? - Ying
That's not impossible, but there is no reason to block the thread. Just break up your code to do whatever you need before the call, make the async call and then do whatever you need when it's done. From that perspective, you can cancel it easily. If you need to block the user interface, you can using a shielding view and a spinner or something, but don't block the thread. - Jason Coco
And even to do that, you absolutely cannot call +sendSynchronousRequest:returningResponse:error: -- if you call that method, you cannot cancel it, not matter what you try. - Jason Coco

3 Answers

6
votes

You cannot cancel it. Simply don't use it and use an asynchronous call instead. Those you can easily cancel.

6
votes

This seemed to work for me:

NSURL *url = [NSURL URLWithString:@"http://someurl.com"];
NSURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5];
NSHTTPURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL];
if (response == nil) {
    // timed out or failed
} else {
    // all good
}

Ofcourse setting the timeout interval to how long you want it to block the main thread before timing out - The above code successfully timed out after 5 seconds

Tested in iOS6 & iOS5.1

1
votes
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url    cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0];

webData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&err];

if (webData==nil) {
        [self displayAlert:@"Time Out" message:@"Request Timed Out"];
    }

Timeout in exactly 10 seconds.