What triggers offscreen rendering, blending and layoutSubviews in iOS?
cocoa, core-animation, ios, iphone
Solution
Offscreen rendering / Rendering on the CPU
The biggest bottlenecks to graphics performance are offscreen rendering and blending – they can happen for every frame of the animation and can cause choppy scrolling.
Offscreen rendering (software rendering) happens when it is necessary to do the drawing in software (offscreen) before it can be handed over to the GPU. Hardware does not handle text rendering and advanced compositions with masks and shadows.
The following will trigger offscreen rendering:
Any layer with a mask (`layer.mask`)
Any layer with `layer.masksToBounds` / `view.clipsToBounds` being true
Any layer with `layer.allowsGroupOpacity` set to YES and `layer.opacity` is less than 1.0 When does a view (or layer) require offscreen rendering?
Any layer with a drop shadow (`layer.shadow*`). Tips on how to fix: https://markpospesel.wordpress.com/tag/performance/
Any layer with `layer.shouldRasterize` being true
Any layer with `layer.cornerRadius`, `layer.edgeAntialiasingMask`, `layer.allowsEdgeAntialiasing`
Any layer with `layer.borderWith` and `layer.borderColor`? Missing reference / proof
Text (any kind, including `UILabel`, `CATextLayer`, `Core Text`, etc).
Most of the drawings you do with `CGContext` in `drawRect:`. Even an empty implementation will be rendered offscreen.
Blending
`resizableImage` can cause blending. Avoiding blended layers when using resizableImages on iOS
Any layer which is not `opaque` and has a `backgroundColor` with `alpha` less than 1.0
Any layer with `alpha` less than 1.0
Any layer with `layer.content` or any `UIImageView` with a `UIImage` having an alpha channel
Layout
The following things will trigger `layoutSubviews` to be called on a UIView:
Changing `bounds` triggers on the same view and superview
Changing `frame` triggers on the same view and superview
Changing `transform` or `layer.transform` triggers on superview
Note: I'm referring to real changes where values actually are changing
Contradictory these changes does not trigger `layoutSubviews` to be called: `center`, `layer.position`, `layer.zPosition`, `layer.anchorPoint`, `layer.anchorPointZ`.
Reference: https://github.com/hfossli/LayoutSubviewsInconsistency
General tips for improving performance
Oftentimes it is better to `blend` than to `render offscreen`.
Consider using `drawRect:` instead of having a view with multiple labels and subviews.
Draw on a background queue to a `UIImage` or `CGImageRef`.
Draw to a `CGLayer` (which is cached better on `GPU` compared to `UIImage`), and draw whatever you want into it. Update, don't: http://iosptl.com/posts/cglayer-no-longer-recommended/
Flatten your hierarchy
Reuse views – don't create and add new ones while scrolling
Have `opaque` views with solid background color
Avoid setting `alpha` and `layer.opacity` to less than 1.0
Enable `layer.shouldRasterize` (use with care). I like to avoid this personally, but it performs faster in some occasions since rasters of the layer will be cached and reused. Remember if you enable `shouldRasterize` on layers that changing their content or sublayers contents frequently will cause the performance to drop, since iOS will keep rasterizing the layer on each change.
Links
http://iosinjordan.tumblr.com/post/56778173518/help-my-tables-dont-scroll-smoothly
https://developer.apple.com/library/IOS/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/DrawingTips/DrawingTips.html
Problem
Exactly what performance-critical things should I have an eye out for? I want a list with as many examples as possible. Or a list of best practices.