views:

918

answers:

5
-(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)

+1  A: 

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

Amuck
Ok. But How to pass NSDictionary?
sugar
Done, See, My answer.
sugar
+7  A: 

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.

Dave DeLong
+2  A: 

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.

Chuck
+5  A: 

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.

bbum
Don't you think, Sir, It's a bit complex-way for the solution.Isn't their any small trick?
sugar
The simplest way, See the comment below my question - or see my answer.
sugar
Simple is not always best. Your answer certainly works but I'd hate to have to maintain or refactor that code. At the same time, quick hacks often pay the bills more effectively than elegant code. ;)
bbum
@bbum, what's wrong in answer?
sugar
sugar
+2  A: 
- (void)startMyTimer {
    /* ... Some stuff ... */
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(callMyMethod:) userInfo:[NSDictionary dictionaryWithObjectsAndKeys:someValue, @"value1", someOtherValue, @"value2", nil] repeats:YES];
}
- (void)callMyMethod:(NSTimer *)theTimer {
    NSString *value1 = [[theTimer userInfo] objectForKey:@"value1"];
    NSString *value2 = [[theTimer userInfo] objectForKey:@"value2"];
    [self myMethod:value1 setValue2:value2];    
}
sugar
Upvoted; a hack... assuredly... but sometimes a hack is all you need. *clap*
bbum
I didn't say it was wrong. I upvoted it. Works fine... the *hack* refers to the fact that it is doing boxing/unboxing and, thus, all type safety is lost and that also increases fragility. Not wrong; just something to be aware of.
bbum
I should have used the term 'hacque' to denote that it is a first class hacque. :)
bbum