CALayers v. CGLayers, or, Which Layer, Player?

What’s the Deal?

An evergreen source of confusion for developers new to graphics on iOS is the existence of multiple Apple-provided graphics frameworks, and multiple “layer” objects within those frameworks.  We’re told to use Core Animation for compositing and animation, and Core Graphics for two-dimensional bitmap drawing (as well as rarer things like low-level text layout and PDF rendering).  Core Animation’s basic class is the CALayer, and Core Graphics has its own CGLayer object.  Surely they are analogous!  Might we construct an SAT-style comparison?

CALayer : CA :: CGLayer : CG?

Despite one’s intuition, not even close.  This is just an unfortunate naming scheme that has wasted countless developer hours and spawned innumerable forum threads.  Let’s take a look at the differences.


Yup, this one you’ll want to know about.  CALayer is one of the most important classes on iOS, right up there with UITableView.  The entire windowing system on iOS runs on top of Core Animation; this means that every single thing you see on screen lives in a CALayer.  They can be positioned, transformed in three(ish*) dimensional space, and a bunch of other neat stuff.  Perhaps most importantly, they can be filled with arbitrary bitmap content – and this is where the confusion sets in.  That bitmap content is often provided by Core Graphics!  When putting Core Graphics content into a CALayer, surely a CGLayer is the right way to go?


Haven’t you been listening?


CGLayers are super cool drawing optimization objects – on the desktop.  Their main use is to cache drawing stuff – either bits or, for instance, PDF drawing commands – for re-use.  They make things like drawing a sprite for a game much faster, for a few reasons.  First, their contents can be stored on the graphics card, meaning that drawing them to the screen is super fast as compared to a bitmap stored in memory.  Second, they are constructed with a specific drawing context in mind, so they can optimize their contents for the format of that context.  And third, since drawing them into a context is so much faster than drawing an arbitrary bitmap, they can enable high-speed animation the Core Graphics way (re-rendering the screen each frame).

Thing is, these advantages don’t carry over to iOS.  When you set a CALayer’s contents, or draw into it, that bitmap is always stored on the graphics card.  That’s just the nature of Core Animation, as a framework built on top of OpenGL.  And practically speaking, there is really only one format you’ll be drawing into – that’s the nature of a closed ecosystem of devices with one optimal pixel format.  (If your app constructs PDFs on the device, this is not the blog post for you.)  As far as animation goes, well, it’s called Core Animation for a reason.  What it comes down to is that in iOS, using a CGLayer buys you nothing but additional complexity.


Don’t use CGLayers on iOS.

* a subject for another post!

Joel Kraut

About Joel Kraut

Developing on Apple platforms for, holy shit, over ten years now. Find me on linkedin and twitter. My personal website is
This entry was posted in Explanation and tagged , , , . Bookmark the permalink.

2 Responses to CALayers v. CGLayers, or, Which Layer, Player?

  1. fg says:

    But what if you wish to store Sprites in iOS and re-draw them on a CALayer? Would you then use CGLayers for the sprites or simply still rely on bitmap drawing on top of CALayers?

    • foon says:

      In my experience, even when using sprites the best way to go is to set the contents of the CALayer to be a CGImageRef. That minimizes the CPU use involved in the drawing and compositing. If you want to use CGLayers because you’re doing drawing and compositing in the layer, try and see if there’s some way you can have CA do the compositing for you–by stacking layers, for instance. Performance will most likely be better, and CPU use definitely will be. You can also get fancy with sprite sheets by playing with the contentsRect property of a CALayer.

Leave a Reply

Your email address will not be published. Required fields are marked *