Canceling a NSURLConnection
Canceling a NSURLConnection
- Subject: Canceling a NSURLConnection
- From: Andreas Grosam <email@hidden>
- Date: Wed, 25 Apr 2012 09:45:43 +0200
Hi All!
I'm having an issue how to properly and reliably canceling a NSURLConnection scheduled on a secondary thread and would really appreciate help.
The actual issue is that sometimes (not always) sending a message from the main thread - which is basically a higher level cancel message - to the thread where the connection delegates are scheduled will block infinitively. I'm sending the message from the main thread via:
[self performSelector:@selector(stopConnectionRunLoop_private)
onThread:self.connectionThread
withObject:nil
waitUntilDone:YES
modes:[NSArray arrayWithObject: NSDefaultRunLoopMode]];
Note the 'YES' for parameter waitUntilDone, which will be explained later.
The main thread blocks infinitively without invoking the selector's message 'stopConnectionRunLoop_private'.
The connection is scheduled in NSDefaultRunLoopMode on the secondary thread, as usual.
Stack (partial):
----------------
Thread 1 Queue : (null) (main thread)
#0 0x35de454c in __semwait_signal ()
#1 0x35d90f78 in _pthread_cond_wait ()
#2 0x35d90918 in pthread_cond_wait ()
#3 0x3517ed64 in -[NSCondition wait] ()
#4 0x3516910c in -[NSObject(NSThreadPerformAdditions) performSelector:onThread:withObject:waitUntilDone:modes:] ()
Thread 6, Queue : (null)
#0 0x35d848d8 in select$DARWIN_EXTSN ()
#1 0x3755aa3a in __CFSocketManager ()
#2 0x35de5b4c in _pthread_start ()
#3 0x35dd77ac in thread_start ()
Thread 7, Queue : (null)
#0 0x35d5b400 in semaphore_wait_trap ()
#1 0x35d91460 in semaphore_wait ()
#2 0x35e5f3cc in _dispatch_semaphore_wait_slow ()
A more detailed explanation:
----------------------------
From the main thread, I invoke this method:
- (void) cancelButtonTapped {
[self cancel];
}
where self is a controller and the connection delegate. -cancel is implemented as follows:
- (void) cancel {
[self cancelConnectionWaitUntilDone:YES];
}
"WaitUntilDone:YES" is a requirement which should guarantee that all delegate methods have finished and the secondary thread has terminated (note, connection delegates execute on the secondary thread). Otherwise, I would possibly risk a race condition due to accessing ivars from the secondary thread and the main thread.
-cancelConnectionWaitUntilDone: is implemented as follows, and yes this seems quite elaborated, but I haven't found an easy way to accomplish this, till now:
- (void) cancelConnectionWaitUntilDone:(BOOL)wait
{
if (self.connection) {
NSLog(@"Attempt to cancel the connection ...");
[self.connection cancel];
self.connection = nil;
NSLog(@"... cancel returned.");
}
else {
NSLog(@"No connection to cancel");
}
[self stopConnectionRunLoopWaitUntilDone:wait]; // here it may block infinitively occasionally
}
Note: the reason for sending a message to the Run Loop is to cause the Run Loop to exit, which in turn can be utilized to check the flag 'runLoopDone_' which causes the outer loop to exit, and eventually causes the secondary thread to exit. Please see the handling of the Run Loop (code fragment) below:
runLoopDone_ = NO;
[[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
if (runLoopDone_) {
NSLog(@"Exit RunLoop.");
}
} while (!runLoopDone_);
- (void) stopConnectionRunLoopWaitUntilDone:(BOOL)wait
{
NSLog(@"stopConnectionRunLoopWaitUntilDone with thread %@", self.connectionThread);
if (self.connectionThread == nil) {
return;
}
[self performSelector:@selector(stopConnectionRunLoop_private)
onThread:self.connectionThread
withObject:nil
waitUntilDone:wait
modes:[NSArray arrayWithObject: NSDefaultRunLoopMode]];
}
- (void) stopConnectionRunLoop_private {
if (self.connection) {
NSLog(@"cannot stop Run Loop: connection is still active");
return;
}
runLoopDone_ = YES;
}
Log:
---
2012-04-25 08:59:07.488 Test[2165:307] Attempt to cancel the connection ...
2012-04-25 08:59:07.532 Test[2165:307] ... cancel returned.
2012-04-25 08:59:07.697 Test[2165:307] stopConnectionRunLoopWaitUntilDone with thread <NSThread: 0x151de0>{name = (null), num = 14}
Thanks for help!
Regards
Andreas
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden