Search code examples
objective-cmacoscocoansviewappkit

What's the difference between CALayerDelegate displayLayer and NSView updateLayer


[CALayerDelegate displayLayer:] is described here.

[NSView updateLayer] is described here.

How do they differ? When would I use one over the other?


Solution

  • -[NSView updateLayer:]

    The purpose of this method is to be overridden by an NSView subclass so that you can customize the backing layer. By default, -[NSView drawRect:] will be used and you're not supposed to manipulate the backing layer directly (like you might with UIView on iOS). If you want to customize the backing layer, you're supposed to use -updateLayer and perform your customizations in this method. To opt into using updateLayer rather than drawRect:, you override -[NSView wantsUpdateLayer] and return YES. Now you can change any property on the backing layer inside of -updateLayer. To notify the view that a change needs to occur you would use the needsDisplay property and set it to YES, which will trigger -updateLayer when it does a render pass. It's also good to know about the layerContentsRedrawPolicy property that controls when a redraw is triggered.

    Example usage:

    @implementation MyView
    
    - (BOOL)wantsUpdateLayer {
        return YES;
    }
    
    - (void)updateLayer {
        // Perform different customizations based on view/control state.
        self.layer.backgroundColor = NSColor.redColor.CGColor;
        self.layer.contents = <some image>;
    }
    
    @end
    
    // Example of notifying MyView instance that it needs to update itself
    myView.needsDisplay = YES;
    

    Shameless plug of a video I did on this topic somewhat recently.

    -[CALayerDelegate displayLayer:]

    This call is specific to CALayer. If you aren't dealing with NSView, then this is how you can be notified of CALayer needing a change as a result of calling -[CALayer setNeedsDisplay].

    In short, if you're dealing with NSView and want to have full control over the backing layer, you must override -wantsUpdateLayer to return YES and implement -updateLayer. If you're directly using CALayers (no NSView involved), then the delegate can be useful here.