NSTimer问题
在我的应用程序中,我使用了下面的代码,定时器的间隔等于 1.0f/30.0f
,这意味着每秒调用 incrementSpeed
30 次。我在日志文件中注意到 moduloResult
的值等于“0”一秒,并且 incrementSpeed
每 5 秒调用 30 次,但我希望它调用每 5 秒只需 1 次。
- (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);
}
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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
通过
self.timescore
,每秒调用inctime:
10 次。每次,它都会将时间变量增加 0.1 秒。因此,时间变量是自计时器开始以来的时间(以秒为单位),四舍五入到最接近的 0.1 秒。例如,如果您这样做,您会得到相同的结果:此行:
在您声明每秒调用 30 次的方法中调用。鉴于它是正数,(int)time 会将“时间”向下舍入到最接近的整数。因此 moduloResult 将有 30 次为“0”——在进入第五秒和再次退出之间的时间段内。正如我在上面发布的代码中所暗示的,您可能想要的是:
即使这样,您也不想将结果直接与 0 进行比较,因为浮点数往往会以不精确的方式进行舍入。如果您每秒调用该方法 30 次,我建议:
因此,当时间 mod 5 为零时,您将检查时间是否在 1/30 秒左右。
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:This line:
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:
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:
So you're checking whether time is within the 1/30th of a second surrounding when time mod 5 is zero.
我不确定我完全理解你想要做什么,但我可以说的是,当你处于精度的边缘时,计时器的行为可能有点不可预测。而你正在这样做。 来自手册:
首先,您无法拥有每 1/30 秒运行一次的计时器。即使是 1/10 秒,也就是您在代码中所说的,也处于可能的边缘。
另请注意,即使晚了,计时器仍然会触发。这可以解释为什么您会看到计时器在您认为应该的时间之后触发。
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:
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.
如果将 float 或 double 转换为 int,则会删除其小数位。所以时间只能是一个整数。所以它总是将整数除以 5,这意味着你永远不会有模数。为什么你实际上将它们转换为整数?尝试将它们都设为双倍,看看是否有帮助。可能是错误的,但我认为它会起作用。
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.