What is the relationship between UIView and CALayer?

7.2.1 · L2 · Interview

Predict first

What are the view’s layer and its delegate?

import UIKit

let v = UIView()
print(type(of: v.layer), v.layer.delegate === v)
  • CALayer true
  • UIView false
  • CALayer false

Predict first

What backs a view that overrides layerClass?

import UIKit

final class GradientView: UIView {
    override class var layerClass: AnyClass { CAGradientLayer.self }
}
print(type(of: GradientView().layer))
  • CALayer
  • CAGradientLayer

Mental model. The view is the stage manager who answers questions and positions things. The layer is the painted backdrop the audience actually sees.

Every UIView owns exactly one backing layer, created from the view’s layerClass (a plain CALayer by default), and the view is that layer’s delegate. The split of work is deliberate. The layer is the unit of rendering: it holds the contents, the geometry, the visual effects (corner radius, shadow, border, masks) and supports implicit animation, and it exists on every Apple platform. The view adds what the layer lacks: event handling (hit testing, responder chain, gestures), the layout system (Auto Layout, layoutSubviews), accessibility and the view hierarchy API. Many view properties simply forward to the layer: frame, bounds, alpha, transform, isHidden.

You reach the layer for things the view does not expose: layer.cornerRadius, layer.shadow…, layer.borderColor, masks and custom animations. Override layerClass to change what backs the view, for example a CAGradientLayer or CAShapeLayer, which is more efficient than adding a sublayer. Layers themselves have no hit testing, no gestures and no Auto Layout, so keep behaviour in the view and rendering in the layer. A layer’s implicit animations are disabled for the view’s own backing layer outside an animation block, which is why property changes on a view jump unless you animate them.

A plain view is backed by a CALayer, and the view itself is the layer’s delegate.

The view creates its backing layer from layerClass, so no extra sublayer is needed.

Common traps

  • Adding a gradient as a sublayer and forgetting to resize it. Sublayers get no Auto Layout; override layerClass or set the frame in layoutSubviews.
  • Assuming CALayer receives touches. It has no event handling; that belongs to the view.

They might follow up with

  • Why does layer.cornerRadius sometimes need masksToBounds? The radius rounds the background and border, and clipping contents needs the mask, which has a rendering cost.
  • Where do the details of rendering live? In the layout, rendering and animation section.

Related questions

  • 7.2.2 What is the difference between frame and bounds, and what happens to them under a transform?
  • 7.1.1 How does UIKit decide which view receives a touch, and why can a subview outside its parent’s bounds not be…
  • 6.3.1 What is a run loop, and what happens in one iteration?

What is the difference between frame and bounds, and what happens to… →