Xcode/Objective-C:为什么NSTimer有时会变慢/波动?

Ant*_*Mae 4 iphone performance objective-c nstimer

我正在开发一款iPhone游戏,我有一个NSTimer动画显示屏幕上的所有对象:

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

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

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

jus*_*tin 6

为什么会发生这种情况的任何想法?

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

补充说明:

  • NSTimer 分辨率低.
  • 您的工作是在主运行循环上执行的.计时器可能不会在您预期时触发,因为在该线程上的工作正在进行时可能会花费很多时间,从而阻止计时器触发.其他系统活动甚至流程中的线程都可以使这种变化更大.
  • 不同步的更新可能会导致大量不必要的工作或不连贯,因为您在回调中执行的更新会在它们发生后的某个时间发布.这会为更新的计时准确性带来更多变化.当更新未同步时,很容易丢弃帧或执行大量不必要的工作.在优化绘图之后,此成本可能不明显.

出于NSTimer文档(强调我的):

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

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

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

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