• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Canceling a NSURLConnection
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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

  • Follow-Ups:
    • Re: Canceling a NSURLConnection
      • From: Andreas Grosam <email@hidden>
  • Prev by Date: Re: NSComboBox
  • Next by Date: Re: Canceling a NSURLConnection
  • Previous by thread: Re: Losing attachments when saving rtfd
  • Next by thread: Re: Canceling a NSURLConnection
  • Index(es):
    • Date
    • Thread