问题
In my app I used the code below with a timer of interval equal to 1.0f/30.0f
which meant that it is called 30 times per second to call incrementSpeed
. I notice in the log file that the value of moduloResult
is equal to '0' for a second and incrementSpeed
is called 30 times every 5 seconds, but I want it to call it just 1 time for every 5 seconds.
- (void)move:(NSTimer *)theTimer {
// ...
CGFloat moduloResult = (float)((int)time % (int)5);
NSLog(@"mod = %f",moduloResult);
if (!moduloResult) {
[self incrementspeed];
}
//...
}
- (void)inctime:(NSTimer*) thetimer{
time = time + 0.10f;
timeLabel.text = [NSString stringWithFormat:@"%0.1f", time];
}
- (void)initializeTimer:(float)intero {
self.myTimer = [NSTimer scheduledTimerWithTimeInterval:intero target:self
selector:@selector(move:) userInfo:nil repeats:YES];
}
- (void)initializeTime {
float theInter = 1.0f/10.0f;
self.timescore = [NSTimer scheduledTimerWithTimeInterval:theInter target:self
selector:@selector(inctime:) userInfo:nil repeats:YES];
}
-(void)incspeed{
deno += 0.01f;
[fadeTimer invalidate];
self.fadeTimer = nil;
[self settheInterval:1.0f/deno];
[self initializeTimer:[self gettheInterval]];
NSLog(@"deno = %f", deno);
NSLog(@"interv = %f", theInterval);
}
回答1:
Via self.timescore
, inctime:
is called 10 times a second. Each time, it increments the time variable by 0.1 of a second. So the time variable is the time in seconds since the timer began, rounded to the nearest 0.1 of a second. E.g. you'd get the same if you did:
... elsewhere ...
@property (nonatomic, assign) NSTimeInterval startTime;
- (void)initializeTime
{
self.startTime = [NSDate timeIntervalSinceReferenceDate];
}
- (void)move:(NSTimer *)theTimer
{
NSTimeInterval timeSinceInitializeTimeWasCalled =
[NSDate timeIntervalSinceReferenceData] - self.startTime;
// round down the nearest multiple of 0.1 if necessary, e.g.
timeSinceInitializeTimeWasCalled -=
fmod(timeSinceInitializeTimeWasCalled, 0.1);
}
This line:
CGFloat moduloResult = (float)((int)time % (int)5);
Is called in a method that you state is called 30 times a second. Given that it's positive, the (int)time will round 'time' down to the nearest whole number. So moduloResult will be '0' 30 times — in the period between entering the fifth second and exiting it again. What you probably want, as hinted at in the code I posted immediately above, is:
CGFloat moduloResult = fmod(time, 5.0);
And even then you don't want to compare the result directly to 0 because floating point numbers tend to round in ways so as to be non-exact. If you're calling that method 30 times a second, I instead recommend:
CGFloat moduloResult = fmod(time + 1.0 / 60, 5.0);
if(moduloResult < 1.0 / 30.0)
{
}
So you're checking whether time is within the 1/30th of a second surrounding when time mod 5 is zero.
回答2:
I'm not sure I completely understand what you're trying to do, but what I can say is that timers behaviour can be a little unpredictable when you're at the edges of their precision. And you are doing just that. Here from the manual:
Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.
So firstly, you're not going to be able to have a timer that runs every 1/30th of a second. Even 1/10th of a second, which is what you say in your code, is on the edge of what's possible.
Also note that the timer still fires, even if it's late. This could explain why you're seeing the timer fire after the time you think it should.
回答3:
If you convert a float or double to a int, it removes its decimals. So time would be a whole number only. So it will always divide a whole number by 5, which means you will never have a modulo. Why did you actually convert them to ints? Try making them both a double and see if that helps. Might be mistaken, but i think it'll work.
来源:https://stackoverflow.com/questions/5363094/nstimer-problem