CGLayer no longer recommended

I spend a lot of time in the labs at WWDC asking questions and talking with the developers. I sat down the Core Graphics engineers this time and asked them about one of my favorite underused tools: CGLayer, which I discuss at the end of Chapter 6. CGLayer sounds like a great idea: a drawing context optimized specifically for drawing on the screen, with hardware optimization. What could go wrong?

I started to have doubts, though, that CGLayer was always a great win. What if your layers were too large to store in GPU textures? CGLayer is advertised for use as a “stamp” that you repeatedly draw. Moving data to and from the GPU is expensive. Maybe CGLayer doesn’t make sense unless you draw it a certain number of times. The docs give no guidance on this. So I asked the Core Graphics team “When should I be using CGLayer?”

“Never.”

… ??? Never? But for stamping right?

Never.

So we talked some more. It appears that CGLayer was one of those things that sounded great on paper, but just doesn’t always work in practice. Sometimes it’s faster. Sometimes its slower. There’s no easy rule for when it’s going to be faster. Over time it seems they’ve quietly abandoned it without actually deprecating it. I’ve asked that the docs be updated to match Apple’s current recommendation. The CGLayer Reference hasn’t been updated since 2006.

The recommendation I received was to use CGBitmapContext or CALayer for stamping. For the specific example given on pages 131-132, CATextLayer would probably be the best tool. Remember that you can easily clone a CALayer using initWithLayer:. (John Mueller points out below that this isn’t actually supported.)

9 comments

  1. Jim Borden

    What does this mean for the wonderful freehand drawing view that I created with CGLayer? I should have been using CGBitmapContext instead?

    • You certainly shouldn’t rewrite existing, working code to move away from CGLayer. It’s not deprecated. It’s just not getting a lot of development love, so don’t expect it to improve or be the fastest solution for any given problem. The main problem with it is that it might be faster and it might be slower, and it’s really hard to determine which it’s going to be. But as long as it isn’t causing any problem, there’s certainly no reason to consider pulling it out.

      But for new code, I recommend CGBitmapContext or CALayer, depending on what problem you were solving.

      • Jim Borden

        I see! It concerns me that the documentation is 6 years old. Does that mean they haven’t touched it since before the first iPhone came out? Or that they just haven’t changed the interface? If it is the former I have a hard time believing that it will be the best solution for anything at all especially on iOS. Regardless though, thanks for this update. A guy in SO chat mistakenly told me that you said it was going to be deprecated so I immediately flipped out: “WHAT?! When I got my draw times down to 0.15 ms?! NO!” This kind of advanced information has made me want to buy your book though xD.

        Out of curiosity, can you send draw commands to a CALayer like you do to a CGLayer? CALayers are not directly linked to a context, so I think the only choice is CGBitmapContext for that situation, right?

        • As I understand it from the Core Graphics team, they basically haven’t touched it since before the iPhone came out. It was one of those things that sounded really good, but didn’t work out in practice. But it’s not actually broken, so there’s no reason to deprecate it. And as I mentioned, if you have awesome CGLayer code, I don’t see any reason to replace it. CGLayer isn’t *bad*. It’s just not maintained like other parts of CG.

          No, you can’t draw directly on a CALayer the way you can a CGLayer. The recommended solution is a bitmap context. It’s a little unfortunate, because I find them a bit more complicated to create than a CGLayer, but that’s the recommended tool.

  2. Rob,

    Would I be right in assuming that multiple instances of CALayer can share the same content? In the sense that when you set

    layer1.content = aCGImage;
    layer2.content = aCGImage;

    they’re pointing to the same CGImage in memory, as opposed to each layer making its own copy of the image?

    I had an app in mind that would make extensive use of “stamping”, as you call it.

  3. Answering my own question after looking at CALayer header which says
    @property(retain) id contents;
    so the answer is yes (should’ve checked before asking, sorry!)

  4. I have watched the 506 session videos from wwdc and also have download the source demos for the 2012 wwdc. But The code for the paint app from that session was not available. Does anyone have the source code for that app “iOS Paint” from the session? Thanks.

    • I have watched it as well and I found myself frustrated at this moment because the source code is not available. Any luck on your side?

  5. John Mueller

    The last sentence of your post says: “Remember that you can easily clone a CALayer using initWithLayer:.”.
    However, seemingly conflicting with this is the current description of initWithLayer: in the CALayer Class Reference, which says: “For example, do not use this method to initialize a new layer with an existing layer’s content.”
    Is my confusion, or rather the apparent conflict, clear? Any advise on how to make a clone if this isn’t the method?
    Thanks!

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>