-
-
Save zwaldowski/955123 to your computer and use it in GitHub Desktop.
// | |
// 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 |
Very nice, thanks a lot for posting this. Its exactly what I was looking for. Nice clean implementation also. :)
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.
Excuse me, but i can't understand, how to use "cancel Block"?
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?
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.
what about using 'dispatch_get_current_queue()' instead of 'dispatch_get_main_queue()' to be more general ?