繁体   English   中英

如何在目标c中使用timer调用函数时传递参数

[英]How to pass arguments when calling function with timer in objective c

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

在这里设置什么?

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

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

如果你想要使用一组相当复杂的参数来调用方法,我建议将参数捕获到包含配置的东西中,并且可以根据该配置做任何需要做的事情......

像这样的界面的东西:

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。

复制自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];
    }

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

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

使用这些参数创建字典并使用timer userinfo传递该字典。 这将解决您的问题

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM