I'm trying to use a series of CALayers as sublayers to a view that needs a little more fine grained drawing than usual. I've been using CATiledLayer
before, and I thought using sublayers would be easier, if not equally finicky. I figured I perform a [self.layer addSublayer:sublayer]
, set the delegate of that new sublayer and then I draw all I want in the drawLayer:inContext:
method. But to my great surprise, my app crashes on addSubview:
(without IB) or somewhere higher up the call stack (when using IB).
The CALayer reference seems to dictate exactly what I'm doing, yet it crashes every time:
In iOS, if the layer is associated with a UIView object, this property must be set to the view that owns the layer.
But obviously, I'm screwing something up. Thankfully, it's easily reproducible. Can you explain to me how I should be using sublayers with delegate assignments to receive the right drawLayer:inContext:
calls without crashing?
Put this in the class of a custom view put on screen with Interface Builder (or rewrite the init to be called initWithFrame:
):
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
CALayer *sublayer = [CALayer layer];
sublayer.frame = self.layer.bounds;
// Disable or enable this next line to
// resolve or trigger an EXC_BAD_ACCESS crash.
//
sublayer.delegate = self;
[self.layer addSublayer:sublayer];
[self.layer setNeedsDisplay];
}
return self;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGContextSetFillColorWithColor(ctx, [[UIColor greenColor] CGColor]);
CGContextFillRect(ctx, self.bounds);
}
If you run this code, your app will crash. Mind the sublayer.delegate = self
line. If you disable that one, your app will run, but the drawLayer:inContext:
method is never called for that sublayer.
What am I doing wrong?
This does not work because the UIView you are subclassing (I assume it is a UIView) already is the delegate of its own CALayer, it cannot be the delegate of more than one CALayer at once. This post has some more details: