NSTimer有时会在开火日期之前被解雇?

时间:2013-03-15 07:47:50

标签: iphone cocoa-touch cocoa nstimer

我正在设置一个计时器,以13分钟的间隔开火。但计时器似乎是不定期地被解雇。这是一个间歇性的问题。一些用户报告了这个问题,我无法重现这个问题。

- (void)resetIdleTimer
{
    if (_idleTimer)
    {
        [_idleTimer invalidate];
        [_idleTimer release];
        _idleTimer = nil;
    }

    _idleTimer = [[NSTimer scheduledTimerWithTimeInterval:13*60.0
                                                   target:self
                                                 selector:@selector(idleTimerExceeded)
                                                 userInfo:nil
                                                  repeats:NO] retain];
}

- (void)idleTimerExceeded
{
        // do some processing
    [_idleTimer release];
    _idleTimer = nil;
}

根据某些条件,计时器将被重置(resetIdleTimer),但无论如何都会重置计时器13分钟。

当我查看代码时,我只能看到没有将timer参数传递给选择器的问题。我不确定这是否是这个问题的原因?有没有人遇到过这种奇怪的事情? (我将如何更新代码以将计时器作为参数)。 一位用户报告说它刚刚发生4分钟后发生。

3 个答案:

答案 0 :(得分:1)

让我们确认一件事,不将timer参数传递给选择器不会引起任何问题。

这是更新的代码,可以正常使用

@property(nonatomic,strong)NSTimer *myTimer;

 @property(nonatomic,retain)NSTimer *myTimer;

<强>方法

- (void)resetIdleTimer
{

  if ([self.myTimer isValid]) 
        [self.myTimer invalidate];

   self.myTimer = [NSTimer scheduledTimerWithTimeInterval:13*60.0
                                 target:self
                               selector:@selector(idleTimerExceeded)
                               userInfo:nil
                                repeats:NO];
} 
- (void)idleTimerExceeded
{
  NSLog(@"tiggered");
}

答案 1 :(得分:0)

我没有在你的代码中发现任何错误,唯一的想法是用户进入你的类创建一个实例,让我们称之为实例“A”,然后启动计时器,然后在13分钟之前退出你的班级,然后再次输入新的实例“B”,新的计时器开始......

此时用户希望您的计时器方法在13分钟后触发...但是“A”的计时器仍处于待处理状态(因为您关闭课程的方式可能有错误)并执行...

您可以尝试添加一些日志并尝试按照我的说法进行操作,并检查所有日志(特别是如果您输入dealloc,并且idleTimerExceeded打印实例中的日志等于resetIdleTimer中打印的最后一个实例):< / p>

    -(void)resetIdleTimer  {
            if (_idleTimer)
            {
                [_idleTimer invalidate];
                [_idleTimer release];
                _idleTimer = nil;
            }

            NSLog(@"...resetIdleTimer: instance: %p", self);
            _idleTimer = [[NSTimer scheduledTimerWithTimeInterval:13*60.0
                                                           target:self
                                                         selector:@selector(idleTimerExceeded)
                                                         userInfo:nil
                                                          repeats:NO] retain];
             NSLog(@"...resetIdleTimer: _idleTimer: %p", _idleTimer);
       }

        - (void)idleTimerExceeded
        {
                // do some processing
            NSLog(@"...idleTimerExceeded: instance: %p", self);
            NSLog(@"...idleTimerExceeded: _idleTimer: %p", _idleTimer);

            [_idleTimer release];
            _idleTimer = nil;
        }


        -(void) dealloc 
        {
            NSLog(@"...dealloc: instance: %p", self);
            [super dealloc];

        }

只是一个想法......但你可能已经忘记了计时器保留了target:参数中传递的实例(你传递了“self”,所以保留了你的类实例),所以常见的错误就是忘记了关闭类实例时关闭计时器。

正确的方法应该是:

-a root class(AAA)使用计时器实例化您的类(BBB) -BBB启动它的计时器 -AAA想要dealloc / resetIdleTimer类BBB:在释放之前它必须停止/使BBB.timer无效(如果没有定时器保留BBB,并且在定时器触发/执行其方法之前不会释放BBB)

所以,如果是你的情况......添加一个可以从类AAA中调用的方法来停止/使计时器无效,例如:

-(void)stopTimer{
                if (_idleTimer)
                {
                    [_idleTimer invalidate];
                    [_idleTimer release];
                    _idleTimer = nil;
                }
}

答案 2 :(得分:0)

如果您希望计时器在13分钟内完成,可能会有所帮助:

https://stackoverflow.com/a/3519913/1226304