NSTimer 类别 +阻止实现以替换选择器
我对块和 Objective-C 很陌生,我正在尝试使用两者来编写我的第一个类别。我的想法是在 NSTimer 上创建一个类别,它将接收一个块作为参数,并且该块将在选择器调用中使用。现在我有这个。
// NSTimer+Additions.h
#import <Foundation/Foundation.h>
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
代码要点: https://gist.github.com/1065235
一切都编译正常,但我有以下错误:
2011-07-05 14:35:47.068 TesteTimer[37716:903] * 由于以下原因终止应用程序未捕获的异常 'NSInvalidArgumentException',原因:'+[NSTimer theBlock]:无法识别的选择器发送到类 0x7fff70bb0a18'
我怎样才能使这个类别工作?
I am quite 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 that will receive a block as a parameter and this block will be used in the selector call. Right now I have this.
// NSTimer+Additions.h
#import <Foundation/Foundation.h>
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
Gist for the code: https://gist.github.com/1065235
Everything compiles fine but i have the following error:
2011-07-05 14:35:47.068 TesteTimer[37716:903] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[NSTimer theBlock]: unrecognized selector sent to class 0x7fff70bb0a18'
How can I make this category work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
除了错误的目标之外,您的主要缺陷是您使用了静态变量。您将无法支持超过一个计时器。
使用块作为调用方法的参数。
使用关联引用的问题是泄漏,因为没有释放块的好点。
使用关联引用的早期方法
您可以使用
关联引用
将块附加到 NSTimer 的特定实例。Your major flaw besides the wrong target is your use of a static variable. You won't be able to support beyond a single timer.
Using block as argument to the invoked method.
The problem with using associative references was the leak as there was no good point to release the block.
Earlier Approach using associative references
You can use
associative references
to attach the block to that particular instance ofNSTimer
.利用 userInfo 来承载你的区块怎么样? (这是用ARC完成的)
然后添加静态选择器:
What about leveraging userInfo to carry your block? (this is done with ARC)
And then add the static selector of:
这应该可行:
问题是您将新
NSTimer
实例的目标设置为self
。但是,在+ ScheduleTimerWithTimeInterval:repeats:actions:
的上下文中(注意+
),self
是NSTimer
,而不是(正如您可能认为的那样)新创建的 NSTimer 实例。从错误消息中可以看出,您的应用程序崩溃是因为
NSTimer
没有响应类方法+ theBlock
,这当然是正确的,因为您只定义了实例方法- theBlock
。This should work:
The problem is that you're setting the target of the new
NSTimer
instance to beself
. However, in the context of+ scheduleTimerWithTimeInterval:repeats:actions:
(notice the+
),self
isNSTimer
, and not (as you probably thought) your newly-createdNSTimer
instance.As you can see from the error message, your app is crashing because
NSTimer
doesn't respond to the class method+ theBlock
, which is of course correct since you only defined the instance method- theBlock
.