Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Using grand central dispatch to run a callback after a delay, with hacky partial cancellation. Cancelling allows the callback to be deallocated, but doesn't completely clean up what's in GCD.
+(void) runBlock:(VoidBlock)callback
afterDelay:(NSTimeInterval)delayInSeconds
unless:(TOCCancelToken*)unlessCancelledToken {
__block VoidBlock callbackForBlock = callback;
NSObject* lock = [NSObject new];
VoidBlock allowDeallocWrapper = ^{
VoidBlock callbackPeek;
@synchronized(lock) {
callbackPeek = callbackForBlock;
}
if (callbackPeek == nil) return; // cancelled
callbackPeek();
};
const int nanosPerSec = 1000*1000*1000;
// simplification: just assume the double to dispatch_time_t conversion is going to work
dispatch_time_t callTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds / nanosPerSec));
dispatch_after(callTime,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
allowDeallocWrapper);
// Simplification: assuming the cancellation token is not long lived (will discuss)
[unlessCancelledToken whenCancelledDo:^{
@synchronized(lock) {
callbackForBlock = nil;
}
}];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment