Using CALayer Delegate

Preferring to keep the layer delegate methods in my UIView subclass, I use a basic re-delegating delegate class. This class can be reused without customization, avoiding the need to subclass CALayer or create a separate delegate class just for layer drawing.

@interface LayerDelegate : NSObject
- (id)initWithView:(UIView *)view;
@end

with this implementation:

@interface LayerDelegate ()
@property (nonatomic, weak) UIView *view;
@end

@implementation LayerDelegate

- (id)initWithView:(UIView *)view {
    self = [super init];
    if (self != nil) {
        _view = view;
    }
    return self;
}

- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context {
    NSString *methodName = [NSString stringWithFormat:@"draw%@Layer:inContext:", layer.name];
    SEL selector = NSSelectorFromString(methodName);
    if ([self.view respondsToSelector:selector] == NO) {
        selector = @selector(drawLayer:inContext:);
    }

    void (*drawLayer)(UIView *, SEL, CALayer *, CGContextRef) = (__typeof__(drawLayer))objc_msgSend;
    drawLayer(self.view, selector, layer, context);
}

@end

The layer name is used to allow for per-layer custom draw methods. For example, if you have assigned a name to your layer, say layer.name = @"Background";, then you can implement a method like this:

- (void)drawBackgroundLayer:(CALayer *)layer inContext:(CGContextRef)context;

Note, your view will need a strong reference the instance of this class, and it can be used as the delegate for any number of layers.

layerDelegate = [[LayerDelegate alloc] initWithView:self];
layer1.delegate = layerDelegate;
layer2.delegate = layerDelegate;

Leave a Comment