意外と解決策が分かるまで時間がかかったので。
CALayer上でCoreGraphicsを使おうとすると以下のようにdrawLayerをオーバーライドしてそこに描画する。更にsetNeedsDisplayで再描画してやる必要がある。
その際、CALayerのdelegateを自身にセットするとBAD_ACCESSエラーが発生する。
SubView.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.layer.backgroundColor = [UIColor clearColor].CGColor;
_sublayer = [CALayer layer];
_sublayer.delegate = self;
_sublayer.frame = CGRectMake(100, 100, 200, 200);
[self.layer addSublayer:_sublayer];
[_sublayer setNeedsDisplay];
}
return self;
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context {
// Drawing code
}
同じ処理をRootViewController内でやると問題ない。
解決策
http://stackoverflow.com/questions/2015353/using-calayer-delegate
delegate先のクラスを用意してやれば良い。そこでdrawLayerを呼び出す。
SubView.h
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
//追加
@interface MyLayerDelegate : NSObject
@end
//追加ここまで
@interface SubView : UIView
@property(weak, nonatomic) CALayer *sublayer;
@property(strong, nonatomic) MyLayerDelegate *mylayerDelegate; //追加
@end
SubView.m
//追加
@implementation MyLayerDelegate
- (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context
{
CGContextMoveToPoint(context, 30, 30); // 始点
CGContextAddLineToPoint(context, 100, 100); // 終点
CGContextStrokePath(context); // 描画!
UIGraphicsPushContext( context ); //UIBezierPathに必須
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(20,20,50,50)];
CGColorRef color = [[UIColor blueColor] CGColor];
CGContextSetShadowWithColor(context, CGSizeZero, 20.0f, color);
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
[circle fill];
UIGraphicsPopContext(); //UIBezierPathに必須
}
@end
//追加ここまで
@implementation SubView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_mylayerDelegate = [MyLayerDelegate alloc];
self.layer.backgroundColor = [UIColor clearColor].CGColor;
_sublayer = [CALayer layer];
//delegate先をselfではなく用意したクラスにする
_sublayer.delegate = _mylayerDelegate;
_sublayer.frame = CGRectMake(100, 100, 200, 200);
[self.layer addSublayer:_sublayer];
[_sublayer setNeedsDisplay];
}
return self;
}
なお、上記のサブクラス内でBezierPathを使おうとするとエラーになるので実行前にUIGraphicsPushContext、実行後にUIGraphicsPopContextを呼び出す必要がある。