【问题标题】:NSTimer - Non-blocking callbackNSTimer - 非阻塞回调
【发布时间】:2012-08-17 18:50:35
【问题描述】:

我对 Objective-c 有点陌生。所以,如果我的问题或代码看起来很奇怪,那就可以解释原因。我有一个每 0.033 秒触发一次的 NSTimer。

timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(timerCallback) userInfo:nil repeats:YES];

选择器函数如下所示:

BOOL running = false;
- (void) timerCallback
{
   if (running) {
    return;
   }
   running = true;
   //Do some stuff
   running = false;
}

问题是,无论如何保持同步,都必须在这些时间间隔触发 timerCallback 函数。 (略过细节)

但是...事实证明,timerCallback 函数会导致 NSTimer 停止并等待它完成后再恢复?

我有什么选择来维持这个间隔? timerCallback 函数可以在单独的线程中执行吗?有比 NSTimer 更好的选择吗?也许是一个单独的线程开始?

【问题讨论】:

  • 你的意思是定时器没有被重复调用?
  • 如果您无法在您的计时器间隔内执行timerCallback 中的操作,那么您不会创建积压的“工作”,最终会给您带来问题吗?
  • 不,是的。我的意思是,如果 timerCallback 需要 0.1 秒,则 NSTimer 将停止,等待函数完成,然后恢复。结果,我失去了同步。我需要始终保持 0.033 秒的间隔。
  • @trojanfoe - 不,我跳过一两个 timerCallback 调用没有问题。但我真的需要保持间隔。比执行代码更重要。
  • 如果 timerCallback 调度了一个新线程呢?然后在该线程中调用您的代码。

标签: iphone objective-c ios nstimer


【解决方案1】:

我建议使用类似的东西来防止阻塞。

BOOL running = false;
- (void) timerCallback
{
   if (running) {
    return;
   }

  [(NSOperationQueue*)_myOperationQueue addOperationWithBlock:^{
     running = true;
     //do Some Stuff
     running = false 
  }];
}

【讨论】:

  • 实现了一个dispatch_queue_t,它现在似乎解决了这个问题。将与此方法进行比较,看看哪个最便宜。
  • 在此代码中,块将同时运行,因此您需要使用 __block OSAtomic(参见 man 3 atomic)标志来设置和清除“运行”标志。运行的东西在原始代码中有点像红鲱鱼,因为我不相信 NSTimer 不会“堆叠”回调。
【解决方案2】:

计时器将尝试维持所需的平均触发间隔 - 因为由于 NSTimer 和 NSRunLoop 的设计,它无法提供准确的计时。如果您在计时器中的代码占用了 0.033 秒以上,我不确定计时器是否会跳过一个呼叫 - 它可能

试试这个实验 - 设置计时器,然后注释掉您的所有工作,并记录时间。它应该非常接近所需时间。也就是说,在每秒 30 次调用中,如果您完全触摸 UI,这已接近您可以预期获得的最大性能。

最小化变化量的一种策略是将您正在执行的所有代码放在一个块中,然后将其分派到主队列,或者更好的是,将其分派到并发线程。这样您就可以在很短的时间内结束通话。

如果这不适合您,请查看 CADisplayLink。您可以使用此功能获得非常精确的回调,因为它以非常高的优先级运行。但是,您不能在回调中做任何实质性的事情,因为您只能得到一小段时间。但是,您可以将块分派到队列以在主队列(主线程)上进行处理。

【讨论】:

  • 实现了一个dispatch_queue_t,它现在似乎解决了这个问题。以后需要看看哪种方法最便宜。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 2016-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多