LoginSignup
2
2

More than 5 years have passed since last update.

subViewでCALayerのdelegate=selfがエラーになる件について

Posted at

スクリーンショット 2014-05-04 17.03.21.png

意外と解決策が分かるまで時間がかかったので。
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を呼び出す必要がある。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2