Re: How To Safely Invoke a Block
Re: How To Safely Invoke a Block
- Subject: Re: How To Safely Invoke a Block
- From: Tom Davie <email@hidden>
- Date: Wed, 21 Nov 2012 11:09:35 +0000
On 21 Nov 2012, at 10:56, Andreas Grosam <email@hidden> wrote:
> I've defined a class Foo that defines a block via a property:
>
> @property (copy) void (^progressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite);
>
> The property is synthesized by the compiler, ARC enabled.
>
> The block is usually invoked on a private thread for several times until an action finishes (an asynchronous NSURLConnection).
> A client of class Foo should be able to set the block property at any time from any thread - that is it should also be able to set the block to NULL. Now, I'm worried about thread safety.
>
> First, is it a good measurement to use a property with the "atomic" attribute?
Not really, as your block may be released (by the setter) between getting the block and invoking it.
> Secondly, I'm invoking the block as follows (from within a NSURLConnectionDelegate method):
>
> progress_handler_block_t block;
> if ( (block=self.progressHandler) != NULL) {
> block(RXProgressStateStart, 0, self.source.size);
> }
>
>
> since it appears to me, that
>
> if (_progressHandler) {
> _progressHandler(RXProgressStateStart, 0, self.source.size);
> }
>
> or
>
> if (self.progressHandler) {
> self.progressHandler(RXProgressStateStart, 0, self.source.size);
> }
>
> isn't thread safe.
>
>
> Your comments are welcome!
Grand Central Dispatch is your friend.
@implementation MyClass
static dispatch_once_t onceToken;
static dispatch_queue_t dispatchQueue;
typedef (void(^ProgressHandler)(RXProgressState progressState, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite);
- (void)setProgressHandler:(ProgressHandler)progressHandler
{
dispatch_once(&onceToken, ^
{
dispatchQueue = dispatch_queue_create("RXProgressQueue", DISPATCH_QUEUE_SERIAL);
});
dispatch_sync(dispatchQueue, ^()
{
if (_progressHandler != progressHandler)
{
[_progressHandler release];
_progressHandler = [progressHandler copy];
}
});
}
- (void)progressHandler
{
return _progressHandler;
}
- (void)callSite
{
…
dispatch_once(&onceToken, ^
{
dispatchQueue = dispatch_queue_create("RXProgressQueue", DISPATCH_QUEUE_SERIAL);
});
dispatch_sync(dispatchQueue, ^()
{
ProgressHandler handler = [self progressHandler];
handler(…);
});
…
}
Tom Davie
_______________________________________________
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