# Layer Tree

## Layers and Views

Core Animation is a compositing engine; its job is to compose different pieces of visual content on the screen, and to do so as fast as possible.

Core Animation 其实是个合成引擎

we’re going to cover Core Animation’s static compositing and layout features, starting with the layer tree.

静态合成布局特性

UIView handles touch events and supports Core Graphics-based drawing, affine transforms (such as rotation or scaling), and simple animations such as sliding and fading.

UIView 处理事件， 支持 基于Core Graphics的绘制

What you may not realize is that UIView does not deal with most of these tasks itself. Rendering, layout, and animation are all managed by a Core Animation class called CALayer.

渲染，布局，动画全都是由 CALayer 管理

Layers, like views, are rectangular objects that can be arranged into a hierarchical tree. Like views, they can contain content (such as an image, text, or a background color) and manage the position of their children (sublayers). They have methods and properties for performing animations and transforms. The only major feature of UIView that isn’t handled by CALayer is user interaction.

Layers 有着层级结构， 可以包含内容， 管理子视图位置用于执行动画和转换的方法和属性

It is actually these backing layers that are responsible for the display and animation of everything you see onscreen.

UIView is simply a wrapper, providing iOS-specific functionality such as touch handling and high-level interfaces for some of Core Animation’s low-level functionality.

UIView 只是简单的包裹提供iOS特有的功能， 如触摸处理，对Core Animation 低层级接口的封装

Why does iOS have these two parallel hierarchies based on UIView and CALayer? Why not a single hierarchy that handles everything? The reason is to separate responsibilities, and so avoid duplicating code. Events and user interaction work quite differently on iOS than they do on Mac OS; a user interface based on multiple concurrent finger touches (multitouch) is a fundamentally different paradigm to a mouse and keyboard, which is why iOS has UIKit and UIView and Mac OS has AppKit and NSView. They are functionally similar, but differ significantly in the implementation.

Drawing, layout, and animation, in contrast, are concepts that apply just as much to touchscreen devices like the iPhone and iPad as they do to their laptop and desktop cousins. By separating out the logic for this functionality into the standalone Core Animation framework, Apple is able to share that code between iOS and Mac OS, making things simpler both for Apple’s own OS development teams and for third-party developers who make apps that target both platforms.

In fact, there are not two, but four such hierarchies, each performing a different role. In addition to the view hierarchy and layer tree, there are the presentation tree and render tree.

## Layer Capabilities

But with that simplicity comes a loss of flexibility. If you want to do something slightly out of the ordinary, or make use of a feature that Apple has not chosen to expose in the UIView class interface, you have no choice but to venture down into Core Animation to explore the lower-level options.

UIView 提供的对Core Animation接口的封装不够灵活，有时自定义程度高需要直接动用Core Animation

▪ Drop shadows, rounded corners, and colored borders ▪ 3D transforms and positioning ▪ Nonrectangular bounds ▪ Alpha masking of content ▪ Multistep, nonlinear animations

## Working with Layers

A view has only one backing layer (created automatically) but can host an unlimited number of additional layers.

view 只有一个背部图层， 但是可以代理（接待）许多额外的图层

The benefit of using a layer-backed view instead of a hosted CALayer is that while you still get access to all the low-level CALayer features, you don’t lose out on the high-level APIs (such as autoresizing, autolayout, and event handling) provided by the UIView class.

You might still want to use a hosted CALayer instead of a layer-backed UIView in a real- world application for a few reasons, however:

• You might be writing cross-platform code that will also need to work on a Mac.
• 你可能写跨平台的代码，同时在mac上使用。
• You might be working with multiple CALayer subclasses (see Chapter6, “Specialized Layers”) and have no desire to create new UIView subclasses to host them all.
• 你可能同时使用多个CAlayer子类 不想创建一个新的视图子类去代理（接待）他们。
• You might be doing such performance-critical work that even the negligible overhead of maintaining the extra UIView object makes a measurable difference (although in that case, you’ll probably want to use something like OpenGL for your drawing anyway).
• 你可能需要实现对性能要求十分苛刻的代码。

# The backing Image

## The contents Image

CALayer has a property called contents. This property’s type is defined as id, implying that it can be any kind of object. This is true—in the sense that you can assign any object you like to the contents property and your app will still compile—however, in practice, if you supply anything other than a CGImage, then your layer will be blank.

This quirk of the contents property is due to Core Animation’s Mac OS heritage. The reason that contents is defined as an id is so that on Mac OS, you can assign either a CGImage or an NSImage to the property and it will work automatically. If you try to assign a UIImage on iOS, however, you’ll just get a blank layer. This is a common cause of confusion for iOS developers who are new to Core Animation.

The headaches don’t stop there, though. The type you actually need to supply is a CGImageRef, which is a pointer to a CGImage struct. UIImage has a CGImage property that returns the underlying CGImageRef. If you try to assign that to the CALayer contents property directly, though, it won’t compile because CGImageRef is not really a Cocoa object; it’s a Core Foundation type.

Although Core Foundation types behave like Cocoa objects at runtime (known as toll-free bridging), they are not type compatible with id unless you use a bridged cast. To assign the image of a layer, you actually need to do the following:

layer.contents = (__bridge id)image.CGImage;


That was some very simple code, and yet we’ve done something quite interesting here: Using the power of CALayer, we’ve displayed an image inside an ordinary UIView. This isn’t a UIImageView; it’s not designed to display images normally. By manipulating the layer directly, we’ve exposed new functionality and made our humble UIView a lot more interesting.

## contentsGravity （内容重心）

You might have noticed that our snowman looks a bit… fat. The image we loaded wasn’t precisely square, but it’s been stretched to fit the view. You’ve probably seen a similar situation when using UIImageView, and the solution there would be to set the contentMode property of the view to something more appropriate, like this:

view.contentMode = UIViewContentModeScaleAspectFit;


The equivalent property of CALayer is called contentsGravity, and it is an NSString rather than an enum like its UIKit counterpart. The contentsGravity string should be set to one of the following constant values:

kCAGravityCenter kCAGravityTop kCAGravityBottom kCAGravityLeft kCAGravityRight kCAGravityTopLeft
kCAGravityTopRight kCAGravityBottomLeft kCAGravityBottomRight kCAGravityResize kCAGravityResizeAspect kCAGravityResizeAspectFill


## contentsRect (内容矩形)

The following coordinate types are used in iOS:

• Points—The most commonly used coordinate type on iOS and Mac OS. Points are virtual pixels, also known as logical pixels.
• Pixels—Physical pixel coordinates are not used for screen layout, but they are often still relevant when working with images.
• Unit—Unit coordinates are a convenient way to specify measurements that are relative to the size of an image or a layer’s bounds, and so do not need to be adjusted if that size changes. iOS上有以下几种坐标类型：
• 点， 虚拟像素， 逻辑像素
• 像素， 物理像素
• 单元， 单元坐标是一种方便的描述尺寸的方式， 是相对于一个图片的尺寸或者是一个layer的边界，并且不需要去调整如果尺寸改变了

## Custom Drawing

Setting the layer contents with a CGImage is not the only way to populate the backing image. It is also possible to draw directly into the backing image using Core Graphics. The -drawRect: method can be implemented in a UIView subclass to implement custom drawing.

The -drawRect: method has no default implementation because a UIView does not require a custom backing image if it is just filled with a solid color or if the underlying layer’s contents property contains an existing image instance. If UIView detects that the -drawRect: method is present, it allocates a new backing image for the view, with pixel dimensions equal to the view size multiplied by the contentsScale.

If you don’t need this backing image, it’s a waste of memory and CPU time to create it, which is why Apple recommends that you don’t leave an empty -drawRect: method in your layer subclasses if you don’t intend to do any custom drawing.

The -drawRect: method is executed automatically when the view first appears onscreen. The code inside -drawRect: method uses Core Graphics to draw into the backing image, the result will then be cached until the view needs to update it (usually because the developer has called the -setNeedsDisplay method, although some view types will be redrawn automatically whenever a property that affects their appearance is changed [such as bounds]). Although -drawRect: is a UIView method, it’s actually the underlying CALayer that schedules the drawing and stores the resultant image.

-drawRect是 UIView的方法， 但是实际上是 CALayer 计划安排绘制以及存储结果图片

CALayer has an optional delegate property that conforms to the CALayerDelegate protocol. When CALayer requires content-specific information, it requests it from the delegate. CALayerDelegate is an informal protocol, which is a fancy way of saying that there is no actual CALayerDelegate @protocol that you can reference in your class interface. You just add the methods you need and CALayer will call them if present. (The delegate property is just declared as an id, and all the delegate methods are treated as optional.)

CALayer 有一个可选的delegate property， 叫做CALayerDelegate， 当需要特定内容信息，回想这个delegate获取， 这是一个友好的协议， 全部是可选方法。

When it needs to be redrawn, CALayer asks its delegate to supply a backing image for it to display. It does this by attempting to call the following method:

- (void)displayLayer:(CALayer *)layer;


This is an opportunity for the delegate to set the layer contents property directly if it wants to, in which case no further methods will be called. If the delegate does not implement the -displayLayer: method, CALayer attempts to call the following method instead:

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx;


Before calling this method, CALayer creates an empty backing image of a suitable size (based on the layer bounds and contentsScale) and a Core Graphics drawing context suitable for drawing into that image, which it passes as the ctx parameter.

Note a couple of interesting things here:

• We have to manually call -display on blueLayer to force it to be updated. Unlike UIView, CALayer does not redraw its contents automatically when it appears onscreen; it is left to the discretion of the developer to decide when the layer needs redrawing. 当layer已经显示后， 需要显示调用-display使它重新绘制
• The circle that we have drawn is clipped to the layer bounds even though we have not enabled the masksToBounds property. That’s because when you draw the backing image using the CALayerDelegate, the CALayer creates a drawing context with the exact dimensions of the layer. There is no provision made for drawing that spills outside of those bounds. 即使没有设置masksToBounds, 因为背部图片绘制上下文已经声明了一定的尺寸，没法绘制超出这个区域。

So now you understand the CALayerDelegate and how to use it. But unless you are creating standalone layers, you will almost never need to implement the CALayerDelegate protocol. The reason for this is that when UIView creates its backing layer, it automatically sets itself as the layer’s delegate and provides an implementation for -displayLayer: that abstracts these issues away.

When using view-backing layers, you do not need to implement -displayLayer: or -drawLayer:inContext: to draw into your layer’s backing image; you can just implement the -drawRect: method of UIView in the normal fashion, and UIView takes care of everything, including automatically calling -display on the layer when it needs to be redrawn.

# Layer Geometry （图层几何）

This chapter covered the geometry of CALayer, including its frame, position, and bounds, and we touched on the concept of layers existing in three-dimensional space instead of a flat plane. We also discussed how touch handing can be implemented when working with hosted layers, and the lack of support for autoresizing and autolayout in Core Animation on iOS.

# Visual Effects （视觉效果）

This chapter explored some of the visual effects that you can apply programmatically to layers, such as rounded corners, drop shadows, and masks. We also looked at scaling filters and group opacity.

# Transform （转换）

This chapter covered 2D and 3D transforms. You learned a bit about matrix math, and how to create 3D scenes with Core Animation. You saw what the back of a layer looks like and learned that you can’t peer around objects in a flat image. Finally, this chapter demonstrated that when it comes to handling touch events, the order of views or layers in the hierarchy is more significant than their apparent order onscreen.

2D 和 3D转换， 当有事件处理时，视图的顺序，以及视图的层级顺序 比 视图的显示顺序 更加重要。

# Specialized Layers （特别的layers）

This chapter provided an overview of the many specialized layer types and the effects that can be achieved by using them. We have only scratched the surface in many cases; classes such as CATiledLayer or CAEmitterLayer could fill a chapter on their own. However, the key point to remember is that CALayer is a jack-of-all-trades, and is not optimized for every possible drawing scenario. To get the best performance out of Core Animation, you need to choose the right tool for the job, and hopefully you have been inspired to dig deeper into the various CALayer subclasses and their capabilities. 这章讲了一些特殊的视图，以及可以通过这些视图做到的效果。但只是划破表面而已。

# Setting Things in Motion

## Implicit Animations

### Transactions

Core Animation is built on the assumption that everything you do onscreen will (or at least may) be animated. Animation is not something that you enable in Core Animation. Animations have to be explicitly turned off; otherwise, they happen all the time

Core Animation 是被建立在假定你在屏幕上做的所有事情都需要被动画，除非显示关闭，否则动画一直在发生。 (默认有0.25s动画)

The duration of the animation is specified by the settings for the current transaction, and the animation type is controlled by layer actions.

Transactions are the mechanism that Core Animation uses to encapsulate a particular set of property animations.

Core Animation automatically begins a new transaction with each iteration of the run loop. (The run loop is where iOS gathers user input, handles any outstanding timer or network events, and then eventually redraws the screen.) Even if you do not explicitly begin a transaction using [CATransaction begin], any property changes that you make within a given run loop iteration will be grouped together and then animated over a 0.25-second period.

Core Animation 自动开启一个新的事务，在每一次迭代run loop的时候，（run loop 是iOS 汇集用户输入，处理到达的定时器，以及网络事件，然后最终重绘屏幕） 即使你不显示begin一个事务，任何你更改的属性，在run loop迭代中将会被组合在一起进行一个0.25秒周期的动画

Armed with this knowledge, we can easily change the duration of our color animation. It would be sufficient to change the animation duration of the current (default) transaction by using the +setAnimationDuration: method, but we will start a new transaction first so that changing the duration doesn’t have any unexpected side effects. Changing the duration of the current transaction might possibly affect other animations that are incidentally happening at the same time (such as screen rotation), so it is always a good idea to push a new transaction explicitly before adjusting the animation settings.

#### Layer Actions

The animations that CALayer automatically applies when properties are changed are called actions.

1. The layer first checks whether it has a delegate and if the delegate implements the -actionForLayer:forKey method specified in the CALayerDelegate protocol. If it does, it will call it and return the result.
2. If there is no delegate, or the delegate does not implement -actionForLayer:forKey, the layer checks in its actions dictionary, which contains a mapping of property names to actions.
3. If the actions dictionary does not contain an entry for the property in question, the layer searches inside its style dictionary hierarchy for any actions that match the property name.
4. Finally, if it fails to find a suitable action anywhere in the style hierarchy, the layer will fall back to calling the -defaultActionForKey: method, which defines standard actions for known properties.

#### Presentation Versus Model

the layer tree is sometimes referred to as the model layer tree.

The display values of each layer’s properties are stored in a separate layer called the presentation layer, which is accessed via the -presentationLayer method.

Note that the presentation layer is only created when a layer is first committed (that is, when it’s first displayed onscreen), so attempting to call -presentationLayer before then will return nil.

• If you are implementing timer-based animations (see Chapter 11, “Timer-Based Animation”) in addition to ordinary transaction-based animations, it can be useful to be able to find out exactly where a given layer appears to be onscreen at a given point in time so that you can position other elements to correctly align with the animation.
• If you want your animated layers to respond to user input, and you are using the -hitTest: method (see Chapter 3, “Layer Geometry”) to determine whether a given layer is being touched, it makes sense to call -hitTest: against the presentation layer rather than the model layer because that represents the layer’s position as the user currently sees it, not as it will be when the current animation has finished.

# Tuning for Speed （调节速度）

## CPU Versus GPU

### The Stages of an Animation

• Layout 准备视图以及图层层级，以及设置layer的属性 （frame， background color， border，以及其他）
• Display 图层的backing image 绘制， 包含 -drawRect: 以及 -drawLayer:inContext:
• Prepare 准备好需要传给render server的数据，包括解压图片等等
• Commit 打包好图层以及动画属性， 通过进程间通信，传给渲染服务（render server）用于显示

But those are just the phases that take place inside your application—there is still more work to be done before the animation appears onscreen. Once the packaged layers and animations arrive in the render server process, they are deserialized to form another layer tree called the render tree (mentioned in Chapter 1, “The Layer Tree”). Using this tree, the render server does the following for each frame of the animation:

• Calculates the intermediate values for all the layer properties and sets up the OpenGL geometry (textured triangles) to perform the rendering

• Renders the visible triangles to the screen

So that’s six phases in total; the last two are repeated over and over for the duration of the animation. The first five of these phases are handled in software (by the CPU), only the last is handled by the GPU. Furthermore, you only really have direct control of the first two phases: layout and display. The Core Animation framework handles the rest internally and you have no control over it.

### GPU-Bound Operations

• Too much geometry （太多几何元素）
• Too much overdraw （太多重绘）
• Offscreen drawing （离屏绘制）
• Too-large images （太大的图片）

### CPU-Bound Operations

• Layout calculations （布局计算）
• CoreGraphicsdrawing （通过-drawRect：以及-drawLayer：inContext：方法绘制图像）
• Image decompression （图片解压）

### Core Animation 调试

• Color Blended Layers （颜色混合图层）
• Color Hits Green and Misses Red （缓存命中绿色，未命中红色） shouldRasterize：default false. A Boolean that indicates whether the layer is rendered as a bitmap before compositing. Animatable（一个布尔指示是否需要渲染成一张位图，在组合前）
• Color Copied Images 有时backing image创建表示Core Animation强制创建了图片的拷贝，并且将它传给渲染服务render server， 图片拷贝是非常消耗cpu的。
• Color Immediately 图层debug颜色，只10微秒更新一次，有些效果的调试上，这样太慢去发现问题，开启后会每一帧都去更新debug颜色，这样会影响到真实的帧率
• Color Misaligned Images 高亮未对齐的图片 （不是整数的坐标）有时候偶然，比如给一张大图显示缩略图，或者图像模糊的时候，这会很有用。
• Color Offscreen-Rendered Yellow 需要离屏渲染的视图标记为黄色， 如使用了shadowPath or shouldRasterize等属性.
• Flash Updated Regions 高亮进行了重新绘制的区域 （使用了Core Graphics 进行了软件绘制的）

### 目前理解的整体流程

CPU计算布局，加载视图，解压图片，绘制2D图形后，将图层打包传输给渲染模型，遍历渲染树（render tree）将图层（layer）转化为纹理三角，

## Layer Performance

### Inexplicit Drawing (含糊不清的绘制)

The layer backing image can be drawn on-the-fly using Core Graphics, or set directly using the contents property by supplying an image loaded from a file, or drawn beforehand in an offscreen CGContext. In the previous two chapters, we talked about optimizing both of these scenarios. But in addition to explicitly creating a backing image, you can also create one implicitly through the use of certain layer properties, or by using particular view or layer subclasses. It is important to understand exactly when and why this happens so that you can avoid accidentally introducing software drawing if it’s not needed.

layer的背部图片可以使匆匆忙忙的使用Core Graphics绘制，或者是直接设置contents属性，或者是事先在一个离屏的CGContext中绘制。除了显示创建一个背部图片外，你也可以隐式创建通过特定的layer属性，或者是使用特定的视图或者是特定的layer子类。

### Text （文本）

Both CATextLayer and UILabel draw their text directly into the backing image of the layer. These two classes actually use radically different approaches for rendering text: In iOS 6 and earlier, UILabel uses WebKit’s HTML rendering engine to draw its text, whereas CATextLayer uses Core Text. The latter is faster and should be used preferentially for any cases where you need to draw a lot of text, but they both require software drawing and are therefore inherently slow compared to hardware-accelerated compositing.

CATextLayerUILabel 都可以用于将文本直接转为背部图片，但是这两个类其实使用不同的方式来渲染文本，在iOS6或者更早，UILabel使用 webKit的HTML渲染引擎来绘制文本， CATextLayer使用Core Text，后者会比前者更快，并且在绘制大量文本时，更应该使用。但是两者都是使用软件绘制，所以内在的比起硬件加速的合成慢一些。

Wherever possible, try to avoid making changes to the frame of a view that contains text, because it will cause the text to be redrawn. For example, if you need to display a static block of text in the corner of a layer that frequently changes size, put the text in a sublayer instead.

### Rasterization （栅格化）

We mentioned the shouldRasterize property of CALayer in Chapter 4, “Visual Effects,” as a way to solve blending glitches with overlapping translucent layers, and again in Chapter 12, “Tuning for Speed,” as a performance optimization technique when drawing complex layer subtrees.

Enabling the shouldRasterize property causes the layer to be drawn into an offscreen image. That image will then be cached and drawn in place of the actual layer’s contents and sublayers. If there are a lot of sublayers or they have complex effects applied, this is generally less expensive than redrawing everything every frame. But it takes time to generate that rasterized image initially, and it will consume additional memory.

### Offscreen Rendering

Offscreen rendering is invoked whenever the combination of layer properties that have been specified mean that the layer cannot be drawn directly to the screen without pre- compositing. Offscreen rendering does not necessarily imply software drawing, but it means that the layer must first be rendered (either by the CPU or GPU) into an offscreen context before being displayed. The layer attributes that trigger offscreen rendering are as follows:

• Rounded corners(when combined with masksToBounds)

Offscreen rendering is similar to what happens when we enable rasterization, except that the drawing is not normally as expensive as rasterizing a layer, the sublayers are not affected, and the result is not cached, so there is no long-term memory hit as a result. Too many layers being rendered offscreen will impact performance significantly, however.

It can sometimes be beneficial to enable rasterization as an optimization for layers that require offscreen rendering, but only if the layer/sublayers do not need to be redrawn frequently.

For layers that require offscreen rendering and need to animate (or which have animated sublayers), you may be able to use CAShapeLayer, contentsCenter, or shadowPath to achieve a similar appearance with less of a performance impact.

#### CAShapeLayer

Neither cornerRadius nor masksToBounds impose any significant overhead on their own, but when combined, they trigger offscreen rendering. You may sometimes find that you want to display rounded corners and clip sublayers to the layer bounds, but you don’t necessarily need to clip to the rounded corners, in which case you can avoid this overhead by using CAShapeLayer.

cornerRadius 或者 masksToBounds 都会强制造成显著的超负荷，但是将两者组合，他们将会触发离屏渲染，有时候，你想显示圆角以及裁剪sublayer到边界，但是你不不需要裁剪到圆角，这种时候你可以通过使用CAShapeLayer来避免超负荷。

You can get the effect of rounded corners and still clip to the (rectangular) bounds of the layer without incurring a performance overhead by drawing the rounded rectangle using the handy +bezierPathWithRoundedRect:cornerRadius: constructor for UIBezierPath (see Listing 15.1). This is no faster than using cornerRadius in itself, but means that the masksToBounds property no longer incurs a performance penalty.

#### Stretchable Images

Another way to create a rounded rectangle is by using a circular contents image combined with the contentsCenter property mentioned in Chapter 2, “The Backing Image,” to create a stretchable image (see Listing 15.2). In theory, this should be slightly faster to render than using a CAShapeLayer because drawing a stretchable image only requires 18 triangles (a stretchable image is rendered using nine rectangles arranged in a 3x3 grid), whereas many more are needed to render a smooth curve. In practice, the difference is unlikely to be significant.

We mentioned the shadowPath property in Chapter 2. If your layer is a simple geometric shape like a rectangle or rounded rectangle (which it will be if it doesn’t contain any transparent parts or sublayers), it is easy to create a shadow path that matches its shape and this will greatly simplify the calculations that Core Animation has to do to draw the shadow, avoiding the need to precompose the layer offscreen. This makes a huge difference to the performance.

If your layer has a more complex shape, it might be awkward to generate the correct shadow path, in which case you may want to consider pregenerating your shadow as a background image using a paint program. 如果你的图层是一个复杂的形状，或许会难以生成正确的shadowPath， 这种情况, 你需要考虑生成你的shadow成为一张背景图，通过使用绘制程序

### Blending and Overdraw （混合和重绘）

As mentioned in Chapter 12, there is a limit to the number of pixels that the GPU can draw each frame (known as the fill rate), and while it can comfortably draw an entire screen full of pixels, it might begin to lag if it needs to keep repainting the same area multiple times due to overlapping layers (overdraw).

GPU可在每帧绘制的像素点数量是有限制的（填充率），虽然可以舒适的绘制一整个屏幕的像素，但是还是有可能有耽搁延迟如果需要重复画一个相同的区域多次，因为部分重叠的图层（overdraw）。

The GPU will discard pixels in layers that are fully obscured by another layer, but calculating whether a layer is obscured can be complicated and processor intensive. Merging together the colors from several overlapping translucent pixels (blending) is also expensive. You can help to speed up the process by ensuring that layers do not make use of transparency unless they need to. Whenever possible, you should do the following:

• Set the background Color of your view to a fixed, opaque color.
• Set the opaque property of the view to YES.

GPU会丢弃一部分layer的像素（被另外一个layer完全遮盖），但是会计算一个layer是否被遮盖是复杂 计算密集的。合并多个重叠的透明像素的颜色（混合）是非常消耗资源的。你可以加速这个处理通过确认这个图层不需要有透明除非真的有必要。尽可能做到下面两步：

• 设置背景色为固定的不透明颜色
• 设置opaque属性为YES

This reduces blending (because the compositor knows that nothing behind the layer will contribute to the eventual pixel color) and speeds up the calculations for avoiding overdraw because Core Animation can discard any completely obscured layers in their entirety instead of having to test each overlapping pixel individually.

If you are using images, try to avoid alpha transparency unless it is strictly needed. If the image will appear in front of a fixed background color, or a static background image that doesn’t need to move relative to the foreground, you can prefill the image background and avoid runtime blending.

If you are using text, a UILabel with a white background (or any other solid color) is more efficient to draw than one with a transparent background.

Finally, by judicious use of the shouldRasterize property, you can collapse a static layer hierarchy into a single image that doesn’t need to be recomposited each frame, avoiding any performance penalties due to blending and overdraw between the sublayers.

### Reducing Layer Count

Due to the overhead of allocating layers, preprocessing them, packaging them up to be sent over IPC to the render server, and then converting them to OpenGL geometry, there is a practical upper limit on the number of layers you can display onscreen at once.

The exact limit will depend on the iOS device, the type of layer, and the layer contents and properties, but in general once the number of layers runs into the hundreds or thousands, you are going to start to see performance problems even if the layers themselves are not doing anything particularly expensive.

#### Clipping

Before doing any other kind of optimization to your layers, the first thing to check is that you are not creating and attaching layers to the window if they will not be visible. Layers might be invisible for a variety of reasons, such as the following:

• They lie outside of the bounds of the screen, or the bounds of their parent layer.
• They are completely obscured by another opaque layer.
• They are fully transparent.

• 他们在屏幕边界外，或者父图层的边界外。
• 他们完全被另外一个不透明的图层遮盖。
• 他们完全透明

Core Animation does a fairly good job of culling layers that aren’t going to contribute to the visible scene, but your code can usually determine if a layer isn’t going to be needed earlier than Core Animation can. Ideally, you want to determine this before the layer object is ever created, to avoid the overhead of creating and configuring the layer unnecessarily.

Core Animation 有相当不错机制（去除不贡献显示效果的图层），但是你的代码比Core Animation可以更早确认一个图层是否需要。理想状态下，不需要显示的图层不要被创建。

#### Core Graphics Drawing

After you have eliminated views or layers that are not contributing to the display onscreen, there might still be ways that you can reduce the layer count further. For example, if you are using multiple UILabel or UIImageView instances to display static content, you can potentially replace it all with a single view that uses -drawRect: to replicate the appearance of a complex view hierarchy.

It might seem counterintuitive to do this because we know that software drawing is slower than GPU compositing and requires additional memory, but in a situation where the performance is limited by the number of layers, software drawing may actually improve the performance by avoiding excessive layer allocation and manipulation.

Doing the drawing yourself in this case involves a similar performance tradeoff to rasterizing, but means that you can remove sublayers from the layer tree altogether (as opposed to just obscuring them, as you do when using shouldRasterize).

### The -renderInContext: Method

Using Core Graphics to draw a static layout may sometimes be faster than using a hierarchy of UIView instances, but using UIView instances is both more concise and more flexible than writing the equivalent drawing code by hand, especially if you use Interface Builder to do the layout. It would be a shame to have to sacrifice those benefits for the sake of performance tuning.

Fortunately, you don’t have to. Having a large number of views or layers is only a problem if the layers are actually attached to the screen. Layers that are not connected to the layer tree don’t get sent to the render server and won’t impact performance (after they’ve been initially created and configured).

By using the CALayer -renderInContext: method, you can draw a snapshot of a layer and its sublayers into a Core Graphics context and capture the result as an image, which can then be displayed directly inside a UIImageView, or as the contents of another CALayer. Unlike using shouldRasterize—which still requires that the layers be attached to the layer tree—with this approach there is no ongoing performance cost.

Responsibility for refreshing this image when the layer content changes would be up to you (unlike using shouldRasterize, which handles caching and cache invalidation automatically), but once the image has initially been generated, you save significant per- frame performance overhead with this approach versus asking Core Animation to maintain a complex layer tree.

# 名称解释

### BackBoard

iOS6 之后的render sever （渲染服务进程） ， 用于动画以及组合屏幕上的图层