// NSTimer+Additions.h
# import
typedef void (^VoidBlock)();
@interface NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduleTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions;
@end
#import "NSTimer+Additions.h"
static VoidBlock _voidBlock;
@interface NSTimer (AdditionsPrivate) // Private stuff
- (void)theBlock;
@end
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduleTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
[_voidBlock release];
_voidBlock = [actions copy];
NSTimer* timer = [[NSTimer alloc] initWithFireDate:[NSDate date]
interval:theSeconds
target:self
selector:@selector(theBlock)
userInfo:nil
repeats:repeats];
[timer fire];
return [timer autorelease];
}
- (void)theBlock {
_voidBlock();
}
@end
Code points: https://gist.github.com/1065235
Everything is compiled but I have the following error:
2011-07-05 14:35:47.068 TesteTimer [37716:903] *The application was terminated due to the uncaught exception’NSInvalidArgumentException’, reason:'[NSTimer theBlock]: Unrecognized selector sent to class 0x7fff70bb0a18′ p>
How do I make this category work?
Use block as the parameter of the called method.
@interface NSTimer (AdditionsPrivate) // Private stuff
- (void)theBlock:(VoidBlock)voidBlock;
@end
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock:)]];
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
invocation:invocation
repeats:repeats];
[invocation setTarget:timer];
[invocation setSelector:@selector(theBlock:) ];
Block_copy(actions);
[invocation setArg ument:&actions atIndex:2];
Block_release(actions);
return timer;
}
- (void)theBlock :(VoidBlock)voidBlock (
voidBlock();
)
@end
The problem with using associative references is leakage, because there is no benefit to freeing the block.
Early methods use cross-references
You can use associative references
to attach blocks to that particular NSTimer instance.
p>
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock)]];
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
invocation:invocation
repeats:repeats];
[invocation setTarget:timer];
[invocation setSelector:@selector(theBlock)];
objc_setAssociatedObject(timer, @"Block", actions, OBJC_ASSOCIATION_COPY);
return timer;
}
- (void)theBlock {
VoidBlock _voidBlock = (VoidBlock)objc_getAssociatedObject(self, @"Block");
_voidBlock();
}
@end
< /p>
I am very new to blocks and objective-c, I am trying to write my first category using both. My idea is to create a category on NSTimer, which will receive a block as a parameter, this block Will be used for selector calls. Now I have this.
// NSTimer+Additions.h
#import
typedef void (^VoidBlock)();
@interface NSTimer (NSTimer_Additions)
+ (NSTimer * )scheduleTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions;
@end
#import "NSTimer+Additions.h"
static VoidBlock _voidBlock;
@interface NSTimer (AdditionsPrivate) // Private stuff
- (void)theBlock;
@end
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduleTimerWith TimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
[_voidBlock release];
_voidBlock = [actions copy];
NSTimer* timer = [[NSTimer alloc] initWithFireDate:[NSDate date]
interval:theSeconds
target:self
selector:@selector(theBlock)
userInfo:nil
repeats:repeats];
[timer fire];
return [timer autorelease];
}
- (void )theBlock {
_voidBlock();
}
@end
Code points: https://gist.github.com/1065235
Everything compiles well but I have the following error:
2011-07-05 14:35:47.068 TesteTimer [37716:903] *The application was terminated due to an uncaught exception’NSInvalidArgumentException’, Reason:'[NSTimer theBlock]: Unrecognized selector sent to class 0x7fff70bb0a18′
How do I make this class work?
In addition to the wrong goal, your main flaw is that you use static variables. Except for a timer, you will not be able to support it.
p>
Use block as the parameter of the called method.
@interface NSTimer (AdditionsPrivate) // Private stuff
- (void)theBlock:(VoidBlock )voidBlock;
@end
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL )repeats actions:(VoidBlock)actions {
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock:)]];
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
invocation:invocation
repeats:repeats];
[invocation setTarget:timer];
[invocation setSelector:@selector(theBlock:)];
Block_copy( actions);
[invocation setArgument:&actions atIndex:2];
Block_release(acti ons);
return timer;
}
- (void)theBlock:(VoidBlock)voidBlock {
voidBlock();
}
@end
The problem with using associative references is leakage, because there is no benefit in releasing blocks.
Early methods use cross-references< /p>
You can use associative references
to attach blocks to that particular NSTimer instance.
@implementation NSTimer (NSTimer_Additions)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)theSeconds repeats:(BOOL)repeats actions:(VoidBlock)actions {
NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(theBlock) ]];
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:theSeconds
invocation:invocation
repeats:repeats];
[invocation setTarget:timer];
[invocation setSelector :@selector(theBlock)];
objc_setAssociatedObject(timer, @"Block", actions, OBJC_A SSOCIATION_COPY);
return timer;
}
- (void)theBlock {
VoidBlock _voidBlock = (VoidBlock)objc_getAssociatedObject(self , @"Block");
_voidBlock();
}
@end