重复NSTimer锁定UI线程

时间:2011-07-14 04:52:54

标签: objective-c ios multithreading user-interface nstimer

首先,我知道有关于此主题的其他一些StackOverflow问题,但我已经阅读了所有这些问题,但我仍然对如何处理我的情况感到困惑。我可能在这里遗漏了一些明显的东西,如果你能帮助澄清那将非常感激!

我有一个应用程序正在做很多工作来动画视图中的图像 - 主要包括一些图像直线移动一次一两秒。我首先考虑使用UIView animateWithDuration在整个运动过程中制作它们一切都很简单。但我发现这并没有给我很大的力量来拦截这个动作或阻止它或检查它在哪里,所以我废弃了。我的新方法是使用NSTimer,每秒发射20次,进行增量运动。通过这种方式,我也可以(几乎)立即进行干预,以更改动画或停止动画或根据动画的距离等更新状态标签等。

首先......可能有比这更好的方法。随意提出更好的建议!

假设这是可以接受的,我现在的问题是,当这些动画发生时,我无法点击UI上的任何其他控件。我没有回应。它不像它只是缓慢或延迟 - 点击永远不会发生。似乎NSTimer处理完全锁定了UI - 但仅限于新的交互。我在计时器处理方法中对UI所做的更改发生得很好,非常活泼。

据我所知,这不应该发生。但是我也看到this question的评论说如果计时器处理密集,那么可以锁定UI线程。我没有看到我的处理在这里是密集的 - 当然没有资源请求,只是一些数据操作和动画一些对象 - 但我可能是在低估它。

我有什么选择?起初我以为我可能会创建一个新的线程来启动计时器。但我记得读过UI更新必须在主线程上发生。为什么是这样?而且,这真的能解决问题吗?我只是要求设备太多来处理这个计时器以及UI交互?还有什么我想念的吗?

任何和所有建议都将不胜感激。

修改

我刚刚找到了UI阻塞问题的原因。我正在使用带有块的animateWithDuration,但没有设置选项。因此UIViewAnimationOptionAllowUserInteraction未设置。我更改了它以设置此选项,我的UI现在很乐意回应。

尽管如此,我仍然会提出这个问题,以便就我的整体方法提出具体建议。感谢。

3 个答案:

答案 0 :(得分:0)

我不完全确定程序中的所有内容是如何处理的,但您可能只想考虑让一个线程/计时器控制所有对象及其移动。实际上没有必要为每个对象创建单独的线程/计时器,因为这很容易导致问题。

您可以为您的移动项目创建一个类,其中包含一些变量,这些变量包含有关其方向,速度,持续时间等的信息,然后让控制线程/计时器计算并移动对象。然后,您可以干预一个主控制器对象,而不必处理许多其他对象。

答案 1 :(得分:0)

我想你会发现,即使你优化了这个,这样的基于计时器的动画效果也不会很好。

您可能想询问您认为使用CoreAnimation无法执行的具体操作。如果你解决了这些问题,你最终会得到比试图推出自己更好的结果。

答案 2 :(得分:0)

我会考虑使用CADisplayLink。来自文档:

CADisplayLink对象是一个计时器对象,允许您的应用程序将其绘图与显示的刷新率同步。

您的应用程序会创建一个新的显示链接,提供一个目标对象和一个在屏幕更新时调用的选择器。接下来,您的应用程序将显示链接添加到运行循环。

一旦显示链接与运行循环相关联,当需要更新屏幕内容时,将调用目标上的选择器。目标可以读取显示链接的timestamp属性以检索上一帧显示的时间。例如,显示电影的应用程序可能会使用时间戳来计算下一个要显示的视频帧。执行其自己的动画的应用程序可能使用时间戳来确定显示对象在即将到来的帧中的显示位置和方式。 duration属性提供帧之间的时间量。您可以在应用程序中使用此值来计算显示的帧速率,下一帧将显示的大致时间,以及调整绘图行为以便及时准备下一帧以进行显示。

您的应用可以通过将暂停属性设置为YES来禁用通知。此外,如果您的应用程序无法在提供的时间内提供帧,您可能需要选择较慢的帧速率。与跳过帧的应用程序相比,具有较慢但一致的帧速率的应用程序对用户来说更平滑。您可以通过更改frameInterval属性来增加帧之间的时间(并降低视在帧速率)。

当您的应用程序使用显示链接完成时,它应调用invalidate将其从所有运行循环中删除并将其与目标取消关联。

CADisplayLink不应该是子类。