How to pass an argument to a method called in a NSTimer
Asked Answered
T

3

6

I have a timer calling a method but this method takes one paramether:

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(timer) userInfo:nil repeats:YES];

should be

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(timer:game) userInfo:nil repeats:YES];

now this syntax doesn't seems to be right. I tried with NSInvocation but I got some problems:

timerInvocation = [NSInvocation invocationWithMethodSignature:
        [self methodSignatureForSelector:@selector(timer:game)]];

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
        invocation:timerInvocation
        repeats:YES];

How should I use Invocation?

Tweezers answered 2/3, 2011 at 10:32 Comment(0)
R
11

Given this definition:

- (void)timerFired:(NSTimer *)timer
{
   ...
}

You then need to use @selector(timerFired:) (that's the method name without any spaces or argument names, but including the colons). The object you want to pass (game ?) is passed via the userInfo: part:

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval 
                                            target:self 
                                          selector:@selector(timerFired:) 
                                         userInfo:game
                                          repeats:YES];

In your timer method, you can then access this object via the timer object's userInfo method:

- (void)timerFired:(NSTimer *)timer
{
    Game *game = [timer userInfo];
    ...
}
Raveaux answered 2/3, 2011 at 10:41 Comment(0)
S
6

As @DarkDust points out, NSTimer expects its target method to have a particular signature. If for some reason you can't conform to that, you can instead use an NSInvocation as you suggest, but in that case you need to fully initialise it with the selector, target and arguments. Eg:

timerInvocation = [NSInvocation invocationWithMethodSignature:
                   [self methodSignatureForSelector:@selector(methodWithArg1:and2:)]];

// configure invocation
[timerInvocation setSelector:@selector(methodWithArg1:and2:)];
[timerInvocation setTarget:self];
[timerInvocation setArgument:&arg1 atIndex:2];   // argument indexing is offset by 2 hidden args
[timerInvocation setArgument:&arg2 atIndex:3];

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval
                                        invocation:timerInvocation
                                           repeats:YES];

Calling invocationWithMethodSignature on its own doesn't do all that, it just creates an object that is able to be filled in in the right manner.

Southernmost answered 2/3, 2011 at 11:4 Comment(0)
C
2

You can pass NSDictionary with named objects (like myParamName => myObject) through userInfo parameter like this

theTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval 
                                            target:self 
                                          selector:@selector(timer:) 
                                          userInfo:@{@"myParamName" : myObject} 
                                           repeats:YES];

Then in timer: method:

- (void)timer:(NSTimer *)timer {
    id myObject = timer.userInfo[@"myParamName"];
    ...
}
Chart answered 2/3, 2011 at 10:42 Comment(2)
If you need to pass several objects that's the way to go. But if it's just a single object you don't need to encapsulate it into a dictionary.Raveaux
True. I've just seen notifications use userInfo dictionaries so thought to keep consistency.Chart

© 2022 - 2024 — McMap. All rights reserved.