I have been working on tracking down a performance issue in one of our apps. What seems to happen is that sometimes a UIImageView takes seconds to render an image and, because of the way the code is written, this blocks the main thread.
I've tracked down the issue to the fact that the slow images are progressive JPEGs at retina resolutions. For whatever reason, when the file reaches a certain size, decoding the JPEG becomes a very expensive operation.
Anyway, in the course of writing a simple test application, I realized I didn't know how to time how long the draw event takes. It clearly is blocking the main thread, so I decided to just try and time the run loop iteration. Unfortunately, it ended up a bit hackish. Here's the relevant code:
///////////////
//
// 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];
The callback is as follows (more 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];
}
}
So, my question is, basically, how would you do this? I want to be able to drop in different images and run a benchmark to make sure I have a rough idea of how long it takes to run this. I also would like to have it be reasonably consistent and free of jitter.
Hmm, maybe I should just subclass UIImageView and record times around [super drawRect:frame]
?
What would you do?