Reputation: 13967
I'm seeing a situation where sometimes loading a URL fails, but it fails very "badly". When a host is unreachable (i.e. VPN not connected), it seems that +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:]
often hangs with the following backtrace:
(gdb) bt
#0 in mach_msg_trap ()
#1 in mach_msg ()
#2 in __CFRunLoopServiceMachPort ()
#3 in __CFRunLoopRun ()
#4 in CFRunLoopRunSpecific ()
#5 in +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] ()
#6 in -[NSThread main] ()
#7 in __NSThread__main__ ()
#8 in _pthread_start ()
#9 in thread_start ()
I have implemented - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
, but it never gets called.
I am constructing the NSURLRequest as follows:
NSURLRequest *theRequest =
[NSURLRequest requestWithURL:[NSURL URLWithString:url]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0];
So I was assuming that rather than hanging indefinitely, the request should time out after 5 seconds. This is not happening.
I should note that this occurs within a console application for Mac OS X (it's a test framework for an iOS library). I'm wondering if something "strange" is happening with the run loop configuration. (from the trace, it looks like it might be trying to spin up a new run loop from within the run loop it's running in?!)
Any ideas?
Edit: Since this is not a Cocoa application, I'm having to run the run loops by hand. This seems like it's probably part of the problem.
Upvotes: 0
Views: 426
Reputation: 13967
I solved the problem. The issue occurred because I didn't give the run loop enough time. I had some code similar to this:
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow:5];
This only caused the run loop to run for 5 seconds, just enough time for me to NOT get the callback from the URLConnection saying it had failed. I changed it to something more like this, and it worked:
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow:10];
I think the side-effect of this, seen in the backtrace, was that the URLConnection object, upon trying to make its callback, had no way to detect that the run loop had stopped, and in mach_msg_trap
it's likely waiting for a reply it will never receive. I can't fully explain that behavior, but that's the general theory. ;-)
Upvotes: 0
Reputation: 90681
I agree that it seems like the timeout you've provided should kick in. There may be a bug.
You may be able to ameliorate the issue somewhat by checking network reachability before attempting the connection. See the SCNetworkReachability API.
You can also impose a timeout of your own by installing a timer on the run loop – the one you're running on a thread you control, rather than the one the framework is running in the background – and cancelling the connection when it fires.
Upvotes: 1