Create a gist now

Instantly share code, notes, and snippets.

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.

Show comment Hide comment
@malaba

malaba Jul 3, 2013

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

malaba commented Jul 3, 2013

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

@Sabobin

This comment has been minimized.

Show comment Hide comment
@Sabobin

Sabobin Sep 30, 2013

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

Sabobin 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.

Show comment Hide comment
@nyteshade

nyteshade 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.

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.

Show comment Hide comment
@ruslanchek

ruslanchek Jan 10, 2014

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

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

@kallipigous

This comment has been minimized.

Show comment Hide comment
@kallipigous

kallipigous 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?

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.

Show comment Hide comment
@newacct

newacct 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.

newacct 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