【问题标题】:How to measure the draw time of a UIImageView?如何测量 UIImageView 的绘制时间?
【发布时间】:2012-06-21 17:15:44
【问题描述】:

我一直在努力追查我们其中一款应用的性能问题。似乎发生的情况是,有时 UIImageView 需要几秒钟来渲染图像,并且由于代码的编写方式,这会阻塞主线程。

我发现问题在于慢速图像是视网膜分辨率下的渐进式 JPEG。无论出于何种原因,当文件达到一定大小时,解码 JPEG 就成为一项非常昂贵的操作。

无论如何,在写simple test application 的过程中,我意识到我不知道如何计算抽奖事件需要多长时间。它显然阻塞了主线程,所以我决定尝试计算运行循环迭代的时间。不幸的是,它最终有点骇人听闻。以下是相关代码:

///////////////
//
// This bit is used to time the runloop. I don't know a better way to do this
// but I assume there is... for now... HACK HACK HACK. :-)

buttonTriggeredDate_ = [NSDate date];
[[NSRunLoop mainRunLoop] performSelector:@selector(fire:) target:self argument:[NSNumber numberWithInt:0] order:1 modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];

///////////////

NSString* path = [[NSBundle mainBundle] pathForResource:imageName ofType:type];
self.imageView.image = [UIImage imageWithContentsOfFile:path];

回调如下(更骇人听闻!):

- (void)fire:(NSNumber*)counter {
    int iterCount = [counter intValue];
    NSLog(@"mark %d", iterCount);
    NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:buttonTriggeredDate_];

    // We really need the second pass through - if it's less than X, assume
    // it's just that first runloop iteration before the draw happens. Just wait
    // for the next one.
    if (iterCount < 1) {
        iterCount++;
        [[NSRunLoop mainRunLoop] performSelector:@selector(fire:) 
                                          target:self 
                                        argument:[NSNumber numberWithInt:iterCount] 
                                           order:1 
                                           modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
    } else {
        self.statusDisplay.text = [NSString stringWithFormat:@"%@ - Took %f Seconds",
                                   self.statusDisplay.text,
                                   interv];
    }
}

所以,我的问题是,基本上,你会怎么做?我希望能够放入不同的图像并运行基准测试,以确保我大致了解运行它需要多长时间。我也希望它保持合理一致且没有抖动。

嗯,也许我应该只继承 UIImageView 并记录 [super drawRect:frame] 附近的时间?

你会怎么做?

【问题讨论】:

  • 我这样做了 - 问题是实际绘图发生在运行循环的后续迭代中。我认为 setImage: 调用只是将指针设置为 UIImage 并且可能只是调用 setNeedsDisplay 或其他什么,然后在下一个 runloop 上调用 draw。
  • 是的,你可能是对的,我不知道该怎么做,我做了一个应用程序来加载许多大图像,我把所有代码放在另一个线程上,并在主线程上使用 self performSelect 来检查如果它准备好避免阻塞主线程。

标签: iphone ios ipad uiimageview nsrunloop


【解决方案1】:

您可能试图对问题的错误部分进行计时。正如您所怀疑的,问题很可能出在解码中(也可能出在内存分配和复制中)。问题不太可能出在最后的“绘图”步骤本身。

这就是 Instruments 专为解决的问题。启动 Instruments 并寻找您的热点。

作为一种可能的解决方案,如果 Instruments 告诉您解码是阻碍您的原因,您可以考虑在将图像放入视图之前将图像渲染到后台线程上的 CALayer

【讨论】:

  • 谢谢 - 这确实是我最终得到的解决方案。这更像是一个关于试图了解我没有来源的组件绘制多长时间的思想实验。似乎是一个有趣的谜题。也很有用。在调试我的代码的过程中,我需要弄清楚将像素放在屏幕上需要多快,例如,以了解最佳情况可能是什么。
  • 不幸的是(也有点幸运)这是一个比听起来要复杂得多的问题。 drawRect: 实际上并没有“将像素放在屏幕上”。在您提供输入的幕后,有大量的合成正在进行。因此,虽然您可以为drawRect:(或其他单独的方法)计时,但这可能无法告诉您汇总绘制需要多长时间。您可以从 Instrument 中的 Core Animation 仪器以及 OpenGL 仪器中提取一些数据。在 Mac 上,您也可以进行 Quartz Debug,但在 iOS 上不可用。
猜你喜欢
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 2012-06-22
  • 2021-09-27
  • 2014-02-12
相关资源
最近更新 更多