在 Objective C 中使用计时器调用函数时如何传递参数

发布于 2024-08-06 19:20:46 字数 333 浏览 3 评论 0原文

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

这里要设置什么?

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

-(void)setX:(int)x andY:(int)y andObject:(Sprite*)obj
{
    [obj setPosition:CGPointMake(x,y)];
}

Now, I want to call above method, using following timer.

[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector() userInfo:nil repeats:NO];

What to set Here?

How to Pass arguments? (as per my knowledge - selector specifies only the method to invoke)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

゛时过境迁 2024-08-13 19:20:46

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

You'll need to used +[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:] instead. By default, the selector used to fire a timer takes one parameter. If you need something other than that, you have to create an NSInvocation object, which the timer will use instead.

醉生梦死 2024-08-13 19:20:46

如果您有一组相当复杂的参数想要用来调用该方法,我建议将参数捕获到保存配置的东西中,并且可以根据该配置执行任何需要执行的操作

...像这样的接口:

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

虽然代码多了一点,但生成的实现将足够快——可能比 NSInitation 更快,但足够快,因为这会导致绘图——而且更加灵活。我可以很容易地看到将上述内容重构为驱动,例如 CoreAnimation。

If you have a fairly complex set of arguments that you want to use to invoke the method, I would recommend capturing the arguments into something that holds a configuration and can do whatever it is that needs doing based on that configuration...

Something with an interface like this:

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

Usage is quite straightforward:

positionSetter = [PositionSetter positionSetterWithX: 42 y: 21 sprite: mySprite];
[positionSetter performSelector: @selector(applyPosition) withObject: nil afterDelay: 1.0];

While a tad more code, the resulting implementation will be fast enough -- probably faster than NSInvocation, but fast enough to be irrelevant given that this is gonna cause drawing -- and a heck of a lot more flexible. I could easily see refactoring the above into driving, say, CoreAnimation.

坏尐絯℡ 2024-08-13 19:20:46

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

Copied from an answer by 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];
    }
稳稳的幸福 2024-08-13 19:20:46

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

If you use a target-action timer, you can't have the timer directly call an arbitrary method. A timer's action must have a very specific signature. You can pass additional data in the userinfo dictionary and have the timer's action call the method you ultimately want, or you can use the invocation form as Dave said. Personally, I usually do the former, because I find NSInvocations to be annoying and setting one up can actually take more code than just writing an intermediary method.

望笑 2024-08-13 19:20:46

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

You can pass an NSDictionary*, or some other object, as the userInfo and put the arguments in that.

孤寂小茶 2024-08-13 19:20:46

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

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

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

As an alternative to NSTimer, on iOS 4.0+ and 10.6+, you could use Grand Central Dispatch and dispatch sources to do this using a block. Apple has the following code for this in their 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;
}

You could then set up a one-second timer event using code like the following:

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

as long as you store and release your timer when done. This can even let you trigger a timer to execute items on a background thread by using a concurrent queue instead of the main queue used above.

This can avoid the need for boxing and unboxing arguments.

偏爱你一生 2024-08-13 19:20:46

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

Create dictionary with those arguments and pass that dictionary with timer userinfo. That will solve your problem

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文