How to pass arguments when calling a function with timer in object c

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

      

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

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

      

What to install here?

How do I pass arguments? (according to my knowledge - the selector only specifies the calling method)

+2


source to share


7 replies


Copied from Matt Ball 's answer :



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

      

+5


source


Instead, you will need to use +[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:]

. By default, the selector used to start the timer takes one parameter. If you want something different, you need to create an NSInvocation object that will use the timer.



+7


source


If you have a rather complex set of arguments that you want to use to invoke a method, I would recommend capturing the arguments to something that contains a configuration and can do whatever it takes 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

      

The usage is pretty simple:

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

      

While a little more code, the resulting implementation will be fast enough - probably faster than NSInvocation, but fast enough to be irrelevant given that it would cause drawing - and a hell of a lot more flexible. I could easily see the refactoring above in driving a car, say CoreAnimation.

+6


source


If you are using a target action timer, you cannot immediately call the timer of an arbitrary method. A timer action must have a very specific signature. You can pass additional data in the userinfo dictionary and activate the timer action with 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 annoying and set one, it can actually take more code than just writing an intermediate method.

+2


source


You can pass NSDictionary * or some other object as userInfo and put arguments in it.

+1


source


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

      

Then you can set up a one second timer event using the following code:

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 save and release your timer when it's done. It might even allow you to start a timer to execute items on a background thread using a parallel queue instead of the main queue used above.

This can eliminate the need for boxing and unboxing arguments.

0


source


Create a dictionary with these arguments and pass that dictionary using the userinfo timer. This will solve your problem.

0


source







All Articles