-(void)setX:(int)x andY:(int)y andObject:(Sprite*)obj
{
[obj setPosition:CGPointMake(x,y)];
}
现在,我想使用以下计时器调用上面的方法。
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector() userInfo:nil repeats:NO];
在这里设置什么?
如何传递参数? (根据我的知识 - 选择器仅指定要调用的方法)
答案 0 :(得分:7)
您需要使用+[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:]
代替。默认情况下,用于触发计时器的选择器需要一个参数。如果您需要其他内容,则必须创建一个NSInvocation对象,而计时器将使用该对象。
答案 1 :(得分:6)
如果你有一组相当复杂的参数要用于调用方法,我建议将参数捕获到包含配置的东西中,并且可以根据该配置做任何需要做的事情......
带有这样界面的东西:
PositionSetter.h:
@interface PositionSetter : NSObject
{
NSInteger x;
NSInteger y;
Sprite *target;
}
+ positionSetterWithX: (NSInteger) xPos y: (NSInteger) yPos sprite: (Sprite *) aSprite;
- (void) applyPosition;
@end
PositionSetter.m:
@interface PositionSetter()
@property(readwrite, nonatomic) NSInteger x;
@property(readwrite, nonatomic) NSInteger y;
@property(readwrite, nonatomic, retain) Sprite *target;
@end
@implementation PositionSetter
@synthesize x, y, target;
+ positionSetterWithX: (NSInteger) xPos y: (NSInteger) yPos sprite: (Sprite *) aSprite;
{
PositionSetter *positionSetter = [PositionSetter new];
positionSetter.x = xPos;
positionSetter.y = yPos;
positionSetter.target = aSprite;
return [positionSetter autorelease];
}
- (void) applyPosition;
{
[self.target setPosition:CGPointMake(self.x,self.y)];
}
@end
用法很简单:
positionSetter = [PositionSetter positionSetterWithX: 42 y: 21 sprite: mySprite];
[positionSetter performSelector: @selector(applyPosition) withObject: nil afterDelay: 1.0];
虽然代码更多,但最终的实现速度足够快 - 可能比NSInvocation更快,但速度足够快,因为这将导致绘图 - 并且更加灵活。我很容易看到将上述内容重构为驾驶,比如CoreAnimation。
答案 2 :(得分:5)
通过Matt Ball的答案复制:
- (void)startMyTimer {
/* ... Some stuff ... */
NSDictionary *userDict;
userDict = [NSDictionary dictionaryWithObjectsAndKeys:someValue,
@"value1",
someOtherValue,
@"value2", nil];
[NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:@selector(callMyMethod:)
userInfo:userDict
repeats:YES];
}
- (void)callMyMethod:(NSTimer *)theTimer {
NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"];
NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"];
[self myMethod:value1 setValue2:value2];
}
答案 3 :(得分:2)
如果使用目标动作计时器,则不能让计时器直接调用任意方法。计时器的动作必须具有非常特定的签名。您可以在userinfo字典中传递其他数据,并让计时器的操作调用您最终想要的方法,或者您可以使用调用表单,如Dave所说。就个人而言,我通常会做前者,因为我发现NSInvocations很烦人,设置一个实际上可以占用更多代码,而不仅仅是编写中间方法。
答案 4 :(得分:1)
您可以将NSDictionary *或其他一些对象作为userInfo传递,并将参数放入其中。
答案 5 :(得分:0)
作为NSTimer的替代品,在iOS 4.0+和10.6+上,您可以使用Grand Central Dispatch和调度源来使用块来执行此操作。 Apple在Concurrency Programming Guide中有以下代码:
dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block)
{
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
if (timer)
{
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway);
dispatch_source_set_event_handler(timer, block);
dispatch_resume(timer);
}
return timer;
}
然后,您可以使用以下代码设置一秒钟的计时器事件:
dispatch_source_t newTimer = CreateDispatchTimer(1ull * NSEC_PER_SEC, (1ull * NSEC_PER_SEC) / 10, dispatch_get_main_queue(), ^{
[self setX:someValue andY:otherValue andObject:obj];
});
只要您在完成时存储并释放计时器。这甚至可以让你通过使用并发队列而不是上面使用的主队列来触发定时器来执行后台线程上的项目。
这可以避免需要装箱和拆箱参数。
答案 6 :(得分:0)
使用这些参数创建字典,并使用timer userinfo传递该字典。这将解决您的问题