Search code examples
iosobjective-cnstimer

NSTimer - integer multiplying


Ok so recently I made a project which had like a bit of a gravity timer,

int speed = 5;
  NSTimer *gravitytimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(gravity) userInfo:nil repeats:YES];


-(void)gravity {

image.center = CGPointMake(image.center.x, image.center.y - speed)
}

The problem is that the speed keeps multiplying or keeps adding and the image goes faster and faster. I don't know what the problem is. I am a newbie so sorry if this is a bad question. Thanks to all the people who take the time to answer.


Solution

  • When you create a timer, while it will try to call it every 0.01 seconds, you actually have no assurances that it will be called precisely at that rate (i.e. if it takes too long, it may skip one or two; if the main thread is blocked doing something else (and it's quite busy when the app first starts), you may skip quite a few). You can request to update image.center 100 times per second, but you have no guarantee that this is how often it actually will end up getting called.

    If you wanted to use this technique to animate, you do so in a manner that isolates the speed of the animation from the frequency of the timer's selector is actually called. So, you might capture the start time, e.g.

    CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
    CGPoint startPoint = image.center;
    

    And then in your timer routine, you'd capture the elapsed time, multiply your speed times the elapsed time, and go from there:

    -(void)gravity {
        CFAbsoluteTime elapsed = CFAbsoluteTimeGetCurrent() - self.start;
        CGFloat speed  = 100.0;      // e.g. 100 points per second
        CGPoint center = startPoint;
        center.y += (elapsed * speed);
        image.center = center;
    }
    

    As an aside, I assume this is just an exercise in timers. If this were a real animation, there are far more effective ways to do such animation (e.g. block-based animateWithDuration, UIKit Dynamics, and if you really wanted to do something timer-based, you'd often use CADisplayLink rather than a NSTimer). Also, BTW, the frame rate of the display is 60fps, so there's no point in trying to call it more frequently than that.