2012-06-19 39 views
2

我一直在努力追踪我们其中一个应用程序的性能问题。看起来会发生的情况是,有时一个UIImageView需要几秒钟来渲染图像,并且由于代码的写入方式,这会阻塞主线程。如何测量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]; 

回调如下(更多hackiness!):

- (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]左右?

你会怎么做?

+0

你有没有试过这个[[NSDate date] timeIntervalSince1970],得到系统毫秒数,并且imageView在主线程上加载同步,因此你可以得到加载开始和结束之间的跨度。 – Tom

+0

我这样做 - 问题在于实际绘图发生在运行循环的后续迭代中。我认为setImage:call只是设置指向UIImage的指针,可能只是调用setNeedsDisplay或其他东西,然后调用下一个runloop。 – sujal

+0

是的,你可能是正确的,我不知道该怎么做,我做了一个应用程序来加载许多大型图像,我把所有代码放在另一个线程上,并在主线程上使用self performSelect来检查它是否准备好避免阻塞main线。 – Tom

回答

1

您可能会试图解决问题的错误部分。正如你怀疑的那样,这个问题很可能在解码(也可能在内存分配和复制中)。问题不大可能在最终的“绘图”步骤中。

这是仪器专为此问题而设计的一类问题。启动仪器并寻找你的热点。

作为一种可能的解决方案,如果Instruments告诉你解码是阻碍你的,你可以考虑在后台线程上将图像渲染到CALayer,然后将它们放入视图中。

+0

谢谢 - 这确实是我最终的解决方案。这更多的是一个关于试图了解一个我没有资源来绘制的组件的想法实验。看起来像一个有趣的谜题。也很有用。在调试我的代码的过程中,我需要弄清楚在屏幕上放置像素的速度有多快,例如,了解最佳情况。 – sujal

+0

这不幸(也有点幸运)是一个比听起来更复杂的问题。 “将像素放在屏幕上”实际上不是由'drawRect:'完成的。在你刚刚提供输入的场景后面进行了大量的合成。所以虽然你可以计算你的'drawRect:'(或其他单独的方法),但它可能不会告诉你需要多长时间才能绘制聚合。您可以从乐器中的Core Animation乐器以及OpenGL乐器中提取一些数据。在Mac上,你也可以Quartz Debug,但这在iOS上不可用。 –