UI更改的推荐频率是多少?

时间:2015-10-23 21:53:53

标签: macos cocoa grand-central-dispatch objective-c++

我有一个cocoa应用程序窗口(NSWindow),屏幕上的位置应该经常更新(取决于一些计算)。正如文档中所注意到的,应该在主线程上进行UI更改:

void calculationThread()
{
    while(true)
    {
        calculatePosition();
        if(positionChanged)
        {
            dispatch_async(dispatch_get_main_queue(), ^{ setWindowPos(); });
        }
    }
}

void setWindowPos()
{
    [window setFrame:_newFrame display:YES];
} 

现在我遇到的问题是窗口移动非常缓慢且延迟。在进行一些分析之后,我发现计算过程大约需要40毫秒,这意味着我每秒钟排队积压UI更新25次。 我已经阅读here这可能比处理它们更快,并且应该使用计时器每十分之一秒左右触发更改。但是,对于人眼来说不是太慢(我的意思是,在这种情况下,运动不会延迟,但会滞后造成几乎相同的影响)。 我将欣赏一些关于此的知识分享。其实我的主要两个问题是:

  1. 每秒25-30次UI更新真的很多吗?
  2. 如果是,推荐的UI更改频率是多少?

2 个答案:

答案 0 :(得分:1)

窗口可以在屏幕上移动而没有问题的频率当然取决于用户机器的速度,他们拥有的视频卡,窗口的大小,以及可能还有许多其他因素。对此没有一个好的答案。但是,如果您只是在屏幕上拖动一个窗口,您会发现它可能会非常顺利地移动(除非您的机器非常繁忙或内存非常低或某些东西);我不希望每秒25次在现代Mac上产生问题。事实上,甚至没有接近。

@ RobNapier关于核心动画等的观点很好,但我觉得夸大其词;如果您真正想要这样做,那么使用计时器或其他定期更新更改UI没有任何内在错误。 CoreAnimation是一个使某些类型的动画更容易的工具包;使用它不是必需的,并不适合所有问题。同样,如果你想进行实际同步到屏幕刷新的更改,那么CVDisplayLink很有用,但它听起来并不像你想做的那样。

出于您的目的,您的基本方法似乎很好,但我建议添加NSDate检查,以便在先前的更新小于(例如)1/60之前的更新时跳过更新。毕竟,您的计算机上的计算似乎需要40毫秒,但在其他计算机上可能要快得多;你想把你的画画限制在一个合理的速度,只是为了成为一个好公民。

那么问题是什么呢?我怀疑这个问题可能实际上是你的电话[window setFrame:_newFrame display:YES]。如果您查看该方法的Apple's docs,他们会说“当YES窗口在其视图层次结构中发送displayIfNeeded消息时,会重新绘制所有视图。”每次你调用那个方法,那么,你不仅要移动你的窗口(我收集的是你的意图);你正在重新绘制窗口的所有内容, 很慢。如果您不需要这样做,那么这就是您需要消除的开销。改为调用setFrameOrigin:setFrameTopLeftPoint:(这使得语义清晰,您正在移动窗口而不调整窗口大小或重新绘制窗口),或者只是setFrame:display:传递NO而不是YES PrintWriter,我猜你的性能问题会消失。

如果你确实每次都需要重新绘制窗口内容,那么请编辑问题描述以反映出来。在这种情况下,解决方案必须涉及分析窗口绘制速度缓慢的原因,并找出优化方法,这是一个完全不同的问题。

答案 1 :(得分:0)

正如您所发现的那样,您绝不应该尝试从紧密循环中驱动UI。你应该让UI驱动你。这有三个主要工具。

对于简单的问题,AppKit能够在屏幕上移动窗口。只需致电[NSWindow setFrame:display:animate:]即可。您可以覆盖animationResizeTime:来修改时间。

在许多情况下,AppKit没有给予足够的控制权。在这种情况下,最好的工具几乎总是核心动画。您应该使用Core Animation告诉系统您希望UI元素在哪里结束,以及在什么时间段和路​​径上,并让它完成将它们放在那里的工作。有关如何使用该文档的详细文档,请参阅Core Animation Programming Guide。它侧重于动画CALayer,但NSWindow的技术类似。您将使用[NSWindow setAnimations:]添加动画。查看NSAnimatablePropertyContainer协议(NSWindow符合的协议)以获取更多信息。有关动画NSWindow的简单示例项目,请参阅CIMGF的Just Say No

在少数情况下,您确实需要在屏幕更新频率下手动更新屏幕。我必须强调这种情况是多么罕见。在几乎所有情况下,Core Animation都是正确的工具。但在极少数情况下(例如某些类型的视频),您可以使用CVDisplayLink来处理此问题。每当屏幕想要刷新时,它都会打电话给您,让您有机会更新您的内容以匹配。