NSTimer问题

发布于 2024-10-24 18:52:57 字数 1280 浏览 7 评论 0原文

在我的应用程序中,我使用了下面的代码,定时器的间隔等于 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

慢慢从新开始 2024-10-31 18:52:57

通过 self.timescore,每秒调用 inctime: 10 次。每次,它都会将时间变量增加 0.1 秒。因此,时间变量是自计时器开始以来的时间(以秒为单位),四舍五入到最接近的 0.1 秒。例如,如果您这样做,您会得到相同的结果:

... 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);
}

此行:

CGFloat moduloResult = (float)((int)time % (int)5);

在您声明每秒调用 30 次的方法中调用。鉴于它是正数,(int)time 会将“时间”向下舍入到最接近的整数。因此 moduloResult 将有 30 次为“0”——在进入第五秒和再次退出之间的时间段内。正如我在上面发布的代码中所暗示的,您可能想要的是:

CGFloat moduloResult = fmod(time, 5.0);

即使这样,您也不想将结果直接与 0 进行比较,因为浮点数往往会以不精确的方式进行舍入。如果您每秒调用该方法 30 次,我建议:

CGFloat moduloResult = fmod(time + 1.0 / 60, 5.0);
if(moduloResult < 1.0 / 30.0)
{
}

因此,当时间 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:

... 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.

晨光如昨 2024-10-31 18:52:57

我不确定我完全理解你想要做什么,但我可以说的是,当你处于精度的边缘时,计时器的行为可能有点不可预测。而你正在这样做。 来自手册:

由于输入源不同
典型的运行循环管理,
有效解决时间问题
定时器的间隔被限制为 on
50-100 毫秒的量级。如果一个
定时器的触发时间发生在
长标注或运行循环时
在不监视的模式下
计时器,计时器不会触发,直到
下次运行循环检查
定时器。因此,实际时间为
计时器可能会触发
是之后的一段相当长的时间
预定的发射时间。

首先,您无法拥有每 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:

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.

心如荒岛 2024-10-31 18:52:57

如果将 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文