3. IOS Core animation advanced skills


[toc]

Here are some notes on layer optimization from reading advanced iOS Core Animation Tips.

rasterizer

It can solve the mixing failure of overlapping transparent layers and also be used as an optimization method to draw complex layer tree structure. Opening method:

layer.shouldRasterize = YES;
layer.rasterizationScale = [UIScreen mainScreen].scale
Copy the code

ShouldRasterize draws the layer to an off-screen image. This image will then be cached and drawn to the contents and sublayers of the actual layer. If you have a lot of sublayers or complex effects applied, it will be much more worthwhile to do this than to draw all the frames for all the transactions. But rasterizing the raw image takes time and consumes extra memory. Rasterization can provide significant performance benefits when used properly, but it must be avoided on layers with constantly changing content, or its cache benefits will disappear and performance will worsen. Instrument > Core Animation > Color Hits Gree and Misses Red Check to see if the rasterized image is being refreshed frequently (which means layers are not a good choice for rasterization, or if you inadvertently trigger unnecessary changes that cause redraw behavior).

Off-screen rendering

Off-screen rendering is invoked when a mixture of layer attributes is specified that it cannot be drawn directly on screen without pre-composition. Off-screen rendering does not mean software rendering, but it does mean that layers must be rendered in an off-screen context (whether CPU or GPU) before they can be displayed. The following properties of the layer will trigger an off-screen paint:

  • Rounded corners (when andmaskToBoundsUsed together)
  • Layer mask
  • shadow

Off-screen rendering is similar to when we enable rasterization, except that it is not as expensive as rasterization layers, the sublayers are not affected, and the results are not cached, so there is no long-term memory footprint. However, performance can still be affected if too many layers are rendered off-screen. It is sometimes possible to turn on rasterization as an optimization for layers that need to be drawn off-screen, as long as they are not frequently redrawn. For layers that need to be animated and rendered off-screen, you can use CAShapeLayer, contentsCenter or shadowPath to get the same performance with less impact.

CAShapeLayer

Both the cornerRadius and maskToBounds have little performance issues when used independently, but when combined they trigger off-screen rendering. Sometimes when you want to show rounded corners and cut sub-layers along layers, you may find that you don’t need to cut layers along rounded corners. In this case, CAShapeLayer can avoid this problem. All you want is rounded corners and cut along the edges of the rectangle without causing performance problems. In fact, you can use the ready-made UIBezierPath constructor + bezierPathWithRoundedRect: cornerRadius: do not do this than directly with cornerRadius faster, but it avoids the performance problems.

CAShapeLayer *blueLayer = [CAShapeLayer layer]; blueLayer.frame = CGRectMake(50, 50, 100, 100); blueLayer.fillColor = [UIColor blueColor].CGColor; blueLayer.path = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0, 0, 100, 100) cornerRadius:20].CGPath;
 
//add it to our view
[self.layerView.layer addSublayer:blueLayer];
Copy the code

Scalable picture

Another way to create rounded rectangles is to create a scalable image with the contentsCenter property of the circular content image. In theory, this should be faster than use, since only 18 triangles are needed for a stretchable image (one image is rendered from a 3 x 3 grid), however, many need to be rendered into a smooth curve. In practice, there is not much difference between the two.

ContentsCenter is actually a CGRect that defines a fixed border and a stretchable area on the layer. Changing the value of contentsCenter does not affect the display of the canvas unless the size of the layer is changed.

CALayer *blueLayer = [CALayer layer]; blueLayer.frame = CGRectMake(50, 50, 100, 100); Bluelayer. contentsCenter = CGRectMake(0.5, 0.5, 0.0, 0.0); blueLayer.contentsScale = [UIScreen mainScreen].scale; blueLayer.contents = (__bridge id)[UIImage imageNamed:@"Circle"];
//add it to our view
[self.layerView.layer addSublayer:blueLayer];
Copy the code

The advantage of using scalable images is that they can be drawn to any border effect with no additional performance cost. Retractable images can even show rectangular shadows.

shadowPath

If the layer is a simple geometric shape such as a rectangle or rounded rectangle (assuming it does not contain any transparent parts or sub-layers), it is relatively easy to create a shadow path for the corresponding shape, and Core Animation draws the shadow fairly easily, avoiding the need for pre-layout of the layer parts off-screen. This is great for performance. If your layer is a more complex shape, it may be difficult to generate the correct shadow path, in which case you can consider using a drawing software to generate a shadow background beforehand.

Mix and overdraw

A GPU has a maximum limit on how many pixels it can draw per frame (known as the fillrate), which makes it easy to draw all the pixels of an entire screen. However, if the same area needs to be redrawn repeatedly due to overlapping layers, frame drop can occur. The GPU will give up drawing pixels that are completely obscured by other layers, but figuring out if a layer is obscured is also complicated and consumes processor resources. Similarly, the resource consumption of merging transparent overlapping pixels of different layers (i.e., blending) is quite objective. So in order to speed up the process, do not use transparent layers until all the time. In any case, here’s what you should do:

  • Set the properties of the view to a fixed, opaque color
  • Set up theopaqueProperty to YES

This reduces the blending behavior (because the compiler knows that everything behind the layer doesn’t affect the final pixel color) and speeds up the calculation, avoiding overdrawing behavior because Core Animation can discard all layers that are completely covered instead of counting every pixel. If images are used, avoid transparency unless absolutely necessary. Finally, using the shouldRasterize attribute wisely, it is possible to fold a fixed layer system into a single image so that you don’t have to recompose each frame and there are no performance issues due to blending and over-drawing between sublayers.

# Reduce the number of layers

Initializing a layer, processing a layer, packaging it to the rendering engine via IPC, converting it to OpenGL geometry, these are the approximate resource costs of a layer. In fact, there is a limit to the maximum number of layers that can be displayed on the screen at once. The exact number of restrictions depends on the iOS device, layer type, layer content and properties, etc. But in general they can hold hundreds or thousands of them. Before making any layer optimizations, you need to make sure that you are not creating invisible layers. Layers can be invisible in several ways:

  • The layer is outside the screen boundary, or outside the parent boundary.
  • Completely behind an opaque layer.
  • Completely transparent

Invisible layers are created as late as possible (create them when necessary).

Object to recycle

Another trick when dealing with large numbers of similar views or layers is to recycle them. Object recycling is common on iOS; UITableView and UICollectionView are useful and there are many other examples. The basic principle of object reclamation is that you need to create a pool of similar objects. When a specified instance of an object finishes its mission, you add it to the object pool. Every time you need an instance, you pull one out of the pool. Create a new one if and only if the pool is empty. The advantage of doing this is that you avoid constantly creating and releasing objects (which is quite expensive because of the allocation and destruction of memory involved) and you don’t have to assign values to similar instances repeatedly.


  • Color Blended Layers– This option highlights the blending areas of the screen from green to red (i.e., multiple translucent layers) based on the rendering level. Blending can have an impact on GPU performance due to redrawing, and is one of the worst culprits for sliding or animation frame rates.
  • Color Hits Green and Misses Red– When shouldRasterizep is used, the time-consuming layer drawing is cached and rendered as a simple flat image. This option highlights the rasterized layer in red when caching is regenerated. If the cache is frequently regenerated, this means that rasterization can have a negative performance impact.
  • Color Copied Images– Sometimes the generation of host images means that Core Animation is forced to generate images and send them to the render server instead of simply pointing to the original pointer. This option renders these images blue. Copying images is a very expensive operation for both memory and CPU usage, so it should be avoided whenever possible.
  • Color Immediately– Normally Core Animation Instruments debugs the colors of new layers at a rate of 10 times per millisecond. This is clearly too slow for some effects. This option can be used to set it to update every frame (this can affect rendering performance and lead to inaccurate frame rate measurements, so don’t set it all the time).
  • Color Misaligned Images– This will highlight images that have been scaled or stretched and are not properly aligned to pixel boundaries (i.e., non-integer coordinates). Most of these will usually cause the image to zoom out improperly, and if a large image is displayed as a thumbnail, or the image is blurred incorrectly, this option will help you identify the problem.
  • Color Offscreen-Rendered Yellow– This will highlight the layers that need to be rendered off-screen in yellow. These layers will probably need to be optimized using shadowPath or shouldRasterize.
  • Color OpenGL Fast Path Blue– This option will highlight any layer drawn directly with OpenGL. If you just use UIKit or Core Animation’s API, it won’t work. If you use GLKView or CAEAGLLayer, not showing blue blocks means you are forcing the CPU to render extra textures instead of drawing them to the screen.
  • Flash Updated Regions– This option highlights the redrawn content in yellow (i.e., any layer drawn using Core Graphics at the software level). This kind of drawing is slow. If this happens frequently, it means there is a hidden bug or room to improve performance by increasing caching or using alternatives.