IOS – NSTIMER Category Blocks Replacement Selector

I am very new to blocks and objective-c, and 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 *)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′

How do I make this category work?

In addition to the wrong goal, your main flaw is that you use static variables. Except for a timing You will not be able to support it.

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.

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

Leave a Comment

Your email address will not be published.