Toland Hon
Toland Hon

Reputation: 4639

For performance, is it better to hide or remove CALayers on iOS?

This is related to the following question: How to improve performance of CALayer animations?

I currently have a view that can have several hundred CALayers. I know having many CALayers will cause performance degradation limited by the processor, but I wanted to see if someone out there has experimented with several of the following methods and can provide guidance.

To better give you an idea of what I'm trying to do, imagine that I have a dot drawn on my layer. When I zoom in, I want the dot to become a star. When I zoom out, I want the star to go back to being a dot. Now imagine that I have hundreds of these dots.

Redrawing single layer vs Multiple pre-drawn layers

Instead of having 1 single layer where I redraw when the zoom changes, I've been experimenting with having 2 separate layers with it pre-drawn and when the zoom changes, I just hide the one and show the other.

[layer configureWithZoom:zoom];
[layer setNeedsDisplay];

vs

layer1.hidden = (zoom == DEFAULT_ZOOM);
layer2.hidden = (zoom != DEFAULT_ZOOM);

I understand that having a bunch of layers will increase my memory footprint and if I had 50 layers before, I now have 100 layers. But in terms of performance, will this help?

Hiding vs Removing

Given the above, I now have layers that aren't needed at all times. Is it better to hide those layers or remove them?

Setting layer.hidden = YES vs [layer removeFromSuperlayer] when I want it to go away.

Setting layer.hidden = NO vs [superlayer addSublayer:layer] when I want it to come back.

If I hide a layer, but animate the superlayer, is there a performance hit during animations because a sublayer is hidden instead of removed? How does that performance hit compare to adding/removing the sublayers?

Parent layer vs Direct layering

One of the problems with having separate layers is now that I need code to manage them as a unit. Previously changing the layer's position was as simple as layer.position = newCoordinates;. Now I would need to do:

layer1.position = newCoordinates1;
layer2.position = newCoordinates2;

I decided to simplify this and create a parent layer and add both layer1 and layer2 to it. My main layer can now just manipulate the parent layer instead of the individual layers. My parent layer would also handle the logic of which of the 2 layers to show or hide.

However, this now introduces a 3rd layer (at the start we had 1, now we have 3). I'm curious if a layer that has no actual drawing besides its sublayers has any impact on performance. Basically does an empty layer having 2 sublayers have a performance hit compared to having those 2 sublayers added directly to the superlayer.

Any guidance would be appreciated.

Upvotes: 6

Views: 2862

Answers (1)

Max
Max

Reputation: 2749

Redrawing single layer vs Multiple pre-drawn layers

It depends on how you draw here. I assume you're using drawInContext of a CALayer with some custom code? If yes, it will definitely help if the call of this drawing code is not necessary every time you change your zoom level. The memory footprint from having double the layers as before really shouldn't hurt you here.

Hiding vs Removing

I'm working with a similar setup to yours for quite a time now and have hundreds (thousands) of CALayers at the same time on the screen. From my experiments I found out that there is a huge performance hit coming from hidden layers. For me it was always best to completely remove and re-add them later.

This is really really frustrating as it's nowhere said in the docs and usually you'd never come to the idea that a hidden layer costs (a lot of) performance.

Parent layer vs Direct layering

About your third question: I'm not 100 percent sure if your empty layer that functions as a parent for your two layers is a performance hit, but I would guess that it is (from my experience every extra layer that CA has to handle causes it to run slower). The question is: Are you able to do it without a layer in between? Is there a certain order your layers have to be in?

You could write a custom class, subclassing NSObject, that takes your two layers, and that manages everything about them (changing position, removing and adding from superlayer etc). This way you would have an easy interface but no extra layer on screen.

If that is not an option, you could try to use CATransformLayer as a compositiing layer for your two layers. This layer doesn't do anything but be a layer for compositing (and it can be used for 3D). Maybe this one takes less performance than a "normal" CALayer in your scenario.

General performance adivce

If possible, do not use drawInContext to draw your layers. If you can, use CAShapeLayer for your stars, it is much faster and has nice anti-aliasing.

Keep a look at the CPU-meter built into Xcode (not the profiler). There you see the CPU-usage of "other processes". In CA-Apps which need a lot of performance, this "other processes" section is basically the CA-RenderServer (backboardd). Here you can see how much CPU your drawing costs right now.

Otherwise if you're concerned about your memory usage, check out the allocations profiler (this time the real profiler) and check how much memory the different versions of your code (50 vs. 100 layers) take.

Upvotes: 12

Related Questions