2

我有一个简单的 UIView 使用drawRect:. 为了使视图动画,该drawRect方法需要每隔 0.05 秒调用一次,所以我使用了一个重复计时器:

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

我不太了解运行循环、线程以及所有系统的东西,所以我想知道这是否是运行动画的正确方法?这个计时器无休止地重复自己。这是我应该担心的事情吗?这会阻塞主线程吗?我可以做些什么来尽量减少对性能的整体影响?

4

2 回答 2

2

这种方法还不错,但还有其他方法可以做到。

计时器的目标方法必须将计时器作为参数,因此不要直接将其设置为 setNeedsDisplay,而应设置如下方法:

- (void)animationTimerDidFire:(NSTimer *)timer
{
    [myView setNeedsDisplay];
}

如果您的视图始终可见,那么您可以设置并忘记计时器。另一方面,如果它可能因为您切换到不同的视图而消失,您将需要根据需要使计时器无效并重新创建。

应用程序的主线程使用运行循环并调用各种方法来响应事件,例如用户点击、系统通知(例如内存警告)和 I/O 到达。如果运行循环调用的任何东西需要很长时间才能返回,它会阻止队列中的所有内容。当您设置一个计时器时,它会被添加到一个列表中,并且运行循环每次都会检查它;如果其中一个计时器准备就绪,它会调用您的方法。

最终的结果是计时器并不精确:它们可能不会像你喜欢的那样频繁地触发,可能会被延迟调用等等。同样,如果你的应用程序非常简单,主运行循环不会很忙,所以一个计时器可能会足够好。只要确保你的动画是基于调用之间的实际时间,而不是假设每个调用恰好相隔 0.05 秒。

备择方案

如果您的动画仅涉及翻转一些静态图像,则 UIImageView 对此提供了一些支持。

如果创建每一帧动画需要大量时间(并且您不想阻塞主线程),您可以使用后台队列来绘制图像(参见CGBitmapContextCreateCGBitmapContextCreateImage),然后在新的时候向主线程发出信号图像已准备好显示。任何触及视图的事情都必须发生在主线程上,但您可以在背景上进行绘图。

您可能还想阅读CALayerQuartzCore 框架。这是 UIView 对象实际操作以在屏幕上绘制的内容。您可能会发现,您可以通过操作一些 CALayer 对象并让 Core Animation 完成繁重的工作(例如,您将颜色从红色更改为蓝色,Core Animation 负责从一到另一个)。

于 2012-06-25T21:09:18.053 回答
0

好吧,如果您使用重写或自定义方法,则应该使用递归和完成块来调用动画。我发现它比计时器好得多,因为计时器并不总是准确的,如果您将动画定时为循环,可能会导致一些动画问题。

编辑:我不太了解使用 drawRect: 并调用 [self setNeedsDisplay] 来更新它,所以在这方面我无法帮助你。对不起。

于 2012-06-25T21:06:43.660 回答