Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Perform blocks with delays and cancellation
//
// NSObject+Blocks.h
// Filemator
//
// Created by Zachary Waldowski on 4/12/11.
// Copyright 2011 Dizzy Technology. All rights reserved.
//
@interface NSObject (Blocks)
+ (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay;
+ (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay;
- (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay;
- (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay;
+ (void)cancelBlock:(id)block;
@end
//
// NSObject+Blocks.m
// Filemator
//
// Created by Zachary Waldowski on 4/12/11.
// Copyright 2011 Dizzy Technology. All rights reserved.
//
#import "NSObject+Blocks.h"
#import <dispatch/dispatch.h>
static inline dispatch_time_t dTimeDelay(NSTimeInterval time) {
int64_t delta = (int64_t)(NSEC_PER_SEC * time);
return dispatch_time(DISPATCH_TIME_NOW, delta);
}
@implementation NSObject (Blocks)
+ (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
if (!block) return nil;
__block BOOL cancelled = NO;
void (^wrappingBlock)(BOOL) = ^(BOOL cancel) {
if (cancel) {
cancelled = YES;
return;
}
if (!cancelled)block();
};
wrappingBlock = [[wrappingBlock copy] autorelease];
dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{ wrappingBlock(NO); });
return wrappingBlock;
}
+ (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay {
if (!block) return nil;
__block BOOL cancelled = NO;
void (^wrappingBlock)(BOOL, id) = ^(BOOL cancel, id arg) {
if (cancel) {
cancelled = YES;
return;
}
if (!cancelled) block(arg);
};
wrappingBlock = [[wrappingBlock copy] autorelease];
dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{ wrappingBlock(NO, anObject); });
return wrappingBlock;
}
- (id)performBlock:(void (^)(void))block afterDelay:(NSTimeInterval)delay {
if (!block) return nil;
__block BOOL cancelled = NO;
void (^wrappingBlock)(BOOL) = ^(BOOL cancel) {
if (cancel) {
cancelled = YES;
return;
}
if (!cancelled) block();
};
wrappingBlock = [[wrappingBlock copy] autorelease];
dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{ wrappingBlock(NO); });
return wrappingBlock;
}
- (id)performBlock:(void (^)(id arg))block withObject:(id)anObject afterDelay:(NSTimeInterval)delay {
if (!block) return nil;
__block BOOL cancelled = NO;
void (^wrappingBlock)(BOOL, id) = ^(BOOL cancel, id arg) {
if (cancel) {
cancelled = YES;
return;
}
if (!cancelled) block(arg);
};
wrappingBlock = [[wrappingBlock copy] autorelease];
dispatch_after(dTimeDelay(delay), dispatch_get_main_queue(), ^{ wrappingBlock(NO, anObject); });
return wrappingBlock;
}
+ (void) cancelBlock:(id)block {
if (!block) return;
void (^aWrappingBlock)(BOOL) = (void(^)(BOOL))block;
aWrappingBlock(YES);
}
@end
@malaba

This comment has been minimized.

Copy link

commented Jul 3, 2013

what about using 'dispatch_get_current_queue()' instead of 'dispatch_get_main_queue()' to be more general ?

@saman-mb

This comment has been minimized.

Copy link

commented Sep 30, 2013

Very nice, thanks a lot for posting this. Its exactly what I was looking for. Nice clean implementation also. :)

@nyteshade

This comment has been minimized.

Copy link

commented Dec 3, 2013

Any chance of having this open sourced for any and all users? Currently your single line copyright, auto added by Xcode, may prevent others from legally using this code that you've written.

@ruslanchek

This comment has been minimized.

Copy link

commented Jan 10, 2014

Excuse me, but i can't understand, how to use "cancel Block"?

@kallipigous

This comment has been minimized.

Copy link

commented Feb 19, 2014

I found using this crashed my app but only when t was compiled for the store. Not ad hoc or debug. Any idea why on earth this might be?

@newacct

This comment has been minimized.

Copy link

commented Dec 12, 2014

The wrappingBlock retains block even after the block has been run or cancelled. It would be a good idea to release it in those cases.

People who use this API will often pass a block that retains some controller object to perform actions on it, and that controller object in turn retains the wrappingBlock returned from this API. This causes a retain cycle that does not automatically get broken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.