NSTimer没有触发

10

我有一个NSTimer,我使用以下代码初始化:

testTimer = [[NSTimer alloc] initWithFireDate:[new objectAtIndex:0] interval:0.0 target:self selector:@selector(works:) userInfo:nil repeats:NO];

[new objectAtIndex:0] 是一个过去的NSDate对象。

当我启动应用程序时,计时器被创建,其fireDate立即触发(因为日期是过去的),但它从未调用我的works:(id)sender方法。

有人知道这是为什么吗?


在这个问题中使用 iPhone 标签是否不合适? - Aravindhan
1
Matt,你可以使用[osx]标签来防止iOS重新标记的大军。 :) - jscs
3个回答

18

如果您使用initWith..方法创建计时器对象,那么您将需要将其添加到当前运行循环中。

NSRunLoop * theRunLoop = [NSRunLoop currentRunLoop];
[theRunLoop addTimer:testTimer forMode:NSDefaultRunLoopMode];

或者如果你想让它为你设置,使用scheduled...方法创建定时器。


4
请注意,使用 alloc/init 创建计时器意味着您拥有该计时器并需要管理其内存,而 scheduledTimer... 方法返回的计时器您不拥有。在任何情况下,它都会被运行循环保留。 - jscs
1
@Josh 这些都是不错的提示。 @Matt 如果要更具体地了解运行循环保留计时器,那么你需要使用 addTimer:forMode: 方法。正如先前所提到的,scheduledTimer... 方法会自动为您完成这个过程,因此运行循环将会保留该计时器。当您调用 invalidate 方法来取消计时器的时候,运行循环将释放该计时器。 - Deepak Danduprolu
1
你说得对,Deepak,我应该更清楚地表明addTimer:...是导致运行循环保留计时器的原因。谢谢。 - jscs

15

我最近遇到了一个NSTimer的问题。在我的情况下,我没有意识到方法scheduledTimerWithTimeInterval不是多线程安全的。一旦我把定时器移到主线程中,它就开始工作了。


1
请问,你是怎么做到的?我遇到了一个问题,它似乎随机触发。 - ari gold
5
尝试将您的NSTimer放入此代码中: dispatch_async(dispatch_get_main_queue(), ^{ });这将确保它在主线程上运行。 - Dobler

3
我认为我遇到了和Dobler一样的问题,但我的解决方案不同。
问题在于计时器是在GCD线程中的块中创建和调度的。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{})

调用函数(实际上是嵌套深层的,因此这一点并不明显)。

使用 NSTimer的scheduledTimerWithTimeInterval:... 函数会将计时器放入无效的运行循环中。

解决方法是改为使用

timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:@selector(...) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接