2
-(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];

在这里设置什么?

如何传递参数?(据我所知 - 选择器仅指定要调用的方法)

4

7 回答 7

7

您需要改为使用+[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:]。默认情况下,用于触发计时器的选择器采用一个参数。如果您需要除此之外的其他内容,则必须创建一个NSInvocation对象,计时器将使用该对象。

于 2009-10-06T18:09:22.987 回答
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。

于 2009-10-06T18:24:47.603 回答
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];
    }
于 2009-10-06T19:14:20.997 回答
2

如果您使用目标动作计时器,则不能让计时器直接调用任意方法。计时器的动作必须有一个非常具体的签名。您可以在 userinfo 字典中传递其他数据并让计时器的操作调用您最终想要的方法,或者您可以使用 Dave 所说的调用表单。就我个人而言,我通常做前者,因为我发现 NSInvocations 很烦人,而且设置一个实际上可能需要更多的代码,而不仅仅是编写一个中间方法。

于 2009-10-06T18:12:47.740 回答
1

您可以将 NSDictionary* 或其他对象作为 userInfo 传递,并将参数放入其中。

于 2009-10-06T18:08:14.363 回答
0

作为 NSTimer 的替代方案,在 iOS 4.0+ 和 10.6+ 上,您可以使用 Grand Central Dispatch 和调度源使用块来执行此操作。Apple 在他们的并发编程指南中有以下代码:

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];
});

只要您在完成后存储并释放计时器。这甚至可以让您通过使用并发队列而不是上面使用的主队列来触发计时器以在后台线程上执行项目。

这可以避免装箱和拆箱参数的需要。

于 2011-12-09T20:42:36.213 回答
0

使用这些参数创建字典并使用计时器 userinfo 传递该字典。这将解决你的问题

于 2012-08-27T11:19:33.850 回答