首先,我知道关于这个主题还有一些其他的StackOverflow问题,但是我已经阅读了它们,我仍然对如何处理我的情况感到困惑。我可能在这里遗漏了一些明显的东西,如果你能帮助澄清,将不胜感激!
我有一个应用程序,它正在做很多工作来动画图像在一个视图-主要是由一些图像在直线上移动一秒钟或两次。我一开始考虑让它们变得简单,在整个运动过程中使用UIView animateWithDuration
的动画。但我发现这并没有给我太多的力量来拦截运动或停止它或检查它的位置,所以我放弃了它。我的新方法是使用NSTimer,每秒发射20次,做增量运动。通过这种方式,我也可以(几乎)立即进行干预,以改变动画或停止它或更新状态标签,基于它通过的距离,等等。
首先……也许有比这更好的办法。请随意提出更好的建议!
假设这是可以接受的,我现在的问题是,当这些动画发生时,我不能点击UI上的任何其他控件。我没有得到回应。它也不只是慢或延迟——点击从来没有通过。看起来NSTimer处理完全锁定了UI——但仅限于新的交互。我在计时器处理方法中对UI所做的更改发生得很好,而且非常灵活。
从我读到的,这是不应该发生的。然而,我也看到了一个关于这个问题的评论,说如果计时器处理是密集的,那么它可以锁定UI线程。我不认为我的处理在这里是那么密集—当然没有资源请求,只是一点数据操作和一些对象的动画—但是我可能低估了它。
我在这里有什么选择?起初我想创建一个新线程来启动计时器。但我记得读到过UI更新必须发生在主线程上。为什么会这样?另外,这样真的能解决问题吗?我是否要求设备处理计时器和UI交互太多了?我还遗漏了什么吗?
任何建议都将不胜感激。
编辑:我刚刚找到了我的UI阻塞问题的原因。我使用animateWithDuration
块,但没有设置选项。因此没有设置UIViewAnimationOptionAllowUserInteraction
。我把它改为设置这个选项,我的UI现在很高兴地响应了。
也就是说,我仍然会留下这个问题,征求关于我的总体方法的具体建议。谢谢。
我会考虑使用CADisplayLink。来自文档:
CADisplayLink对象是一个计时器对象,它允许应用程序将其绘图与显示的刷新率同步。
您的应用程序创建了一个新的显示链接,提供了一个目标对象和一个选择器,以便在屏幕更新时调用。接下来,您的应用程序将显示链接添加到运行循环中。
一旦显示链接与运行循环相关联,当需要更新屏幕内容时,将调用目标上的选择器。目标可以读取显示链接的时间戳属性来检索前一帧显示的时间。例如,显示电影的应用程序可能会使用时间戳来计算下一个要显示的视频帧。执行自己动画的应用程序可能会使用时间戳来确定在下一帧中显示的对象出现的位置和方式。duration属性提供帧之间的时间长度。您可以在应用程序中使用此值来计算显示的帧率,下一帧将显示的大致时间,并调整绘图行为,以便及时准备好显示下一帧。
应用程序可以通过将暂停属性设置为YES来禁用通知。此外,如果您的应用程序不能在规定的时间内提供帧,您可能需要选择较慢的帧速率。对于用户来说,具有较慢但一致的帧率的应用程序比跳过帧的应用程序更平滑。您可以通过更改frameInterval属性来增加帧之间的时间(并降低表观帧速率)。
当你的应用程序用一个显示链接结束时,它应该调用invalidate将它从所有的运行循环中移除,并将它与目标分离。
CADisplayLink不应该被子类化
我不完全确定如何在您的程序中处理一切,但您可能只想考虑使用一个线程/计时器来控制所有对象及其运动。真的没有必要为每个对象创建单独的线程/计时器,因为这很容易导致问题。
你可以为你的移动项目创建一个类,其中包含一些关于它们的方向,速度,持续时间等信息的变量,然后有一个控制线程/计时器计算和移动对象。然后,您可以对一个主控制器对象进行干预,而不必处理许多其他对象。
我想你会发现,即使你优化了这个,像这样基于计时器的动画也不会表现得很好。
你可能想问一下你认为你不能用CoreAnimation做的具体事情。如果你解决了这些问题,你最终会得到一个比你自己尝试更好的结果。