Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIImageView displays MUCH faster than either CG or CALayer. Anyone know why?

I've written an app to test image performance on iOS. I've tried 3 different views, all displaying the same large PNG. The first is a view that draws using CGContextDrawImage(). The second sets self.layer.content. The third is a plain UIImageView.

The image used is created using -[UIImage initWithContentsOfData:] and cached in the viewController. Each test repeatedly allocs a view, adds it to the view hierarchy and then removes it and releases it. Timings are taken from the start of loadView to viewDidAppear and given as fps (effectively, view draws per second).

Here are the results from an iPad 1 running 5.1 using a 912 x 634 unscaled image:

CGContext:    11 fps
CALayer:      10 fps
UIImageView: 430 fps (!)

Am I hallucinating? It seems almost impossible that UIImageView can draw that fast, but I can actually watch the images flicker. I tried swapping between two similar views to defeat possible caching, but the frame rate was even higher.

I had always assumed that UIImageView was just a wrapper for -[CALayer setContent]. However, profiling the UIImageView shows almost no time spent in any drawing method that I can identify.

I'd love to understand what's going on. Any help would be most appreciated.

like image 882
John Graziano Avatar asked Apr 19 '12 00:04

John Graziano


2 Answers

Here is my idea.

When you modify a UIView hierarchy, by either adding, removing or modifying some view, no actual drawing is performed yet. Instead the view is marked with 'setNeedsDisplay', and is redrawn the next time the runloop is free to draw.

In fact, if your testing code looks something like this (I can only guess):

for (int i=0; i<10000; i++) {
     UIImageView* imageView = [[UIImageView alloc] initWithFrame:frame];
     [mainView addSubview: imageView];
     [imageView setImage: image];
     [mainView removeSubview: imageView];
}

than the runloop is blocked until this for loop is done. The view hierarchy is drawn only once, the measured performance is that of allocating and initializing objects.

On the other hand, the CGContextDrawImage() is free to draw right away, I think.

like image 170
lukasz Avatar answered Oct 13 '22 21:10

lukasz


The high FpS with UIImageView is because this does not actually redraws, but only marks the content for redrawing sometimes in the future when UIKit feels like doing it.

As a note: What is strange though is, that the CGContextmethod is faster than the CALayermethod. I also tried these methods in a project of mine and working with CALayer is the fastest method (except using OpenGL ES of course).

like image 33
Florian Avatar answered Oct 13 '22 20:10

Florian