Xcode / Objective-C:为什么NSTimer有时会慢/不稳定? [英] Xcode / Objective-C: Why is NSTimer sometimes slow/choppy?

查看:167
本文介绍了Xcode / Objective-C:为什么NSTimer有时会慢/不稳定?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一款iPhone游戏,我有一个 NSTimer ,可以激活屏幕上的所有对象:

I am developing an iPhone game and I have an NSTimer that animates all of the objects on the screen:

EverythingTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 target:self selector:@selector(moveEverything) userInfo:nil repeats:YES];

大部分时间它运行得非常顺利,但有时我看到事情变得缓慢或不稳定。我有暂停和恢复功能,分别停止和启动计时器。当我暂停然后取消暂停时,似乎可以解决这个问题。

Most of the time it runs very smoothly, but sometimes I see things move slower or choppy. I have pause and resume functions that stop and start the timers respectively. When I pause then unpause, it seems to fix the choppiness.

为什么会发生这种情况?或者我该如何解决?

Any ideas to why this is happening? or How can i fix it?

推荐答案


为什么会发生这种情况?

Any ideas to why this is happening?

简而言之,在您的情况下,您正在基于非同步推送模型执行操作(动画),并且您使用的机制是不适合您正在执行的任务。

The short answer is that in your case, you are performing actions (animations) based on an unsynchronized push model, and the mechanism you are using is not suited for the task you are performing.

附加说明:


  • NSTimer 分辨率低。

  • 您的工作是在主运行循环上执行的。计时器可能不会在您预期时触发,因为在该线程上的工作正在进行时可能会花费很多时间,这会阻止计时器触发。其他系统活动甚至流程中的线程都可以使这种变化更大。

  • 由于您在回调中执行的更新(s),不同步的更新可能会导致大量不必要的工作或波动(s) )在它们发生后的某个时间发布。这会为更新的计时准确性带来更多变化。当更新未同步时,很容易丢弃帧或执行大量不必要的工作。在优化绘图之后,此成本可能不会很明显。

  • NSTimer has a low resolution.
  • Your work is performed on the main run loop. The timer may not fire when you expect it to because much time may be spent while work on that thread is underway, which blocks your timer from firing. Other system activities or even threads in your process can make this variation even greater.
  • Unsynchronized updates can result in a lot of unnecessary work, or choppiness because the updates you perform in your callback(s) are posted at some time after they occur. This adds even more variation to the timing accuracy of your updates. It's easy to end up dropping frames or perform significant amounts of unnecessary work when the updates are not synchronized. This cost may not be evident until after your drawing is optimized.

超出 NSTimer docs(强调我的):

Out of the NSTimer docs (emphasis mine):


计时器不是实时机制;只有当添加了计时器的其中一个运行循环模式正在运行并且能够检查计时器的触发时间是否已经过去时,它才会触发。由于典型的运行循环管理各种输入源,定时器的时间间隔的有效分辨率被限制在大约50-100毫秒。如果在长时间标注期间或在运行循环处于不监视计时器的模式下发生计时器的触发时间,则计时器在下次运行循环检查计时器之前不会触发。因此,计时器触发的实际时间可能是预定点火时间后的一段很长时间

A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. 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.

如果您准备优化绘图,解决问题的最佳方法是使用 CADisplayLink ,正如其他人所提到的那样。 CADisplayLink 是iOS上的一个特殊计时器,它以屏幕刷新率的(有能力)除法执行回调消息。这允许您将动画更新与屏幕更新同步。此回调在主线程上执行。注意:此工具在OS X上不太方便,可能存在多个显示( CVDisplayLink )。

The best way to remedy the issue, if you are prepared to also optimize your drawing -- is to use CADisplayLink, as others have mentioned. The CADisplayLink is a special 'timer' on iOS which performs your callback message at a (capable) division of the screen refresh rate. This allows you to synchronize your animation updates with the screen updates. This callback is performed on the main thread. Note: This facility is not so convenient on OS X, where multiple displays may exist (CVDisplayLink).

所以,您可以从创建显示链接开始,在其回调中,执行处理动画和绘制相关任务的工作(例如,执行任何必要的 -setNeedsDisplayInRect:更新)。确保您的工作非常快,并且您的渲染也很快 - 那么您应该能够实现高帧速率。避免在此回调中进行慢速操作(例如文件io和网络请求)。

So, you can start by creating a display link and in its callback, perform work which would deal with your animations and drawing related tasks (e.g. perform any necessary -setNeedsDisplayInRect: updates). Make sure your work is very quick, and that your rendering is also quick -- then you should be able achieve a high frame rate. Avoid slow operations in this callback (e.g. file io and network requests).

最后一点:我倾向于将我的计时器同步回调集群到一个Meta-Callback中,而不是在运行循环上安装许多定时器(例如以不同频率运行)。如果您的实现可以快速确定当前要执行的更新,那么这可能会显着减少您安装的计时器数量(仅限一个)。

One final note: I tend to cluster my timer sync callbacks into one Meta-Callback, rather than installing many timers on run loops (e.g. running at various frequencies). If your implementations can quickly determine which updates to do at the moment, then this could significantly reduce the number of timers you install (to exactly one).

这篇关于Xcode / Objective-C:为什么NSTimer有时会慢/不稳定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆