0

我正在GLKView使用按需渲染构建自定义。大多数情况下,视图只会在触摸事件上重绘(这是有效的),但有时我想在循环中重绘一些简短的动画。

我的第一次尝试是这样的:

-(void)drawRect:(CGRect)rect {
    NSLog(@"Jo");

    glClearColor(1, 0, 0, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    [self setNeedsDisplay];
}

我的理解Android是,这应该尽可能快地清除屏幕并记录大量“Jo”。实际发生的是“Jo”大约每秒记录一次,视图根本不会被清除,但CPUuse 仍然为 0。

如果我改变

[self setNeedsDisplay];

dispatch_async(dispatch_get_main_queue(), ^{
    [self setNeedsDisplay];
});

一切都按预期工作。

据我了解drawRect,无论如何都是从主线程调用的,那么为什么会dispatch_async有所不同呢?

所以现在我有三个问题:

  1. “Jo”日志之间的那一秒发生了什么?
  2. 为什么要dispatch_async有所作为?
  3. 在生产中使用这种方法是不好的做法吗?

非常感谢!

编辑:

还有一件事我不明白。

当我使用该[self setNeedsDisplay];方法时,主队列上的所有其他调用似乎都在挨饿。触摸事件不再触发,并且来自 RestKit 的回调永远不会被传递。[self setNeedsDisplay];不知何故不会在队列的末尾添加,而是在开始时添加?

4

1 回答 1

0

在那一秒钟内,最有可能没有任何事情发生,因为没有任何事情触发重绘。这个管道非常复杂,但是setNeedsDisplay当在主线程上调用时,诸如此类的方法会做更多的工作,因为它会通知窗口层次结构它发生了变化,并将重绘需要重绘的元素。该管道很可能连接到只能从主线程访问的主运行循环。

因此,当您从其他线程调用它时,您确实标记了它需要重绘的视图,但您没有通知运行循环以实际触发重绘过程。

所以:

  1. 真的没什么特别的。它只是在等待。
  2. 它在触发刷新管道时有所作为。
  3. 根本不是一个坏习惯,但是如果以后有更多元素会调用它,请注意如何执行此过程。

对于好的/坏的做法取决于情况,但我会做的是创建一个包含显示链接的类。我会添加 2 种方法,例如retainAnimationreleaseAnimation。这些 2 将增加或减少一个整数值retainAnimationCount,然后覆盖其设置器,以便:

  1. 如果计数从零增加,则显示链接开始
  2. 如果计数减少到零,则显示链接停止

然后,显示链接将调用委托、给定块或简单地硬编码调用给setNeedsDisplay定视图。类本身可以将输出调用恢复到主线程,但可以从任何线程调用释放和保留调用。

编辑:

在您的情况下如何使用此类,您将在动画开始后调用 retain 方法,并在动画完成后调用 release 方法。所有其余的应该已经在类本身中处理。好处主要是如果您有多个“动画”对象,则不会对刷新方法进行额外调用,交错没有问题,何时开始或何时停止,您从哪个线程调用它......但请确保您没有标记保留计数属性,nonatomic因为您仍然应该保持线程安全。

于 2015-06-02T09:16:30.097 回答