Problem with CALayer delegate

  • Hello everyone,

    I'm a very new cocoa developer (I switched two months ago) but an
    experienced (15+ years) developer.

    I'm struggling trying to get a CALayer delegate method, specifically
    drawLayer being called. I am trying to host the CALayer inside an
    NSView that would be the delegate for the CALayer.

    The CALayer is an attribute of my custom NSView called mainLayer.

    Here is the initWithFrame method for my custom NSView:

    -(id) initWithFrame: (NSRect) frameRect
    {
    self = [super initWithFrame:frameRect];

    if (self)
    {
      mainLayer = [[[CALayer alloc] init] retain];

      [mainLayer setDelegate:self];
      [self setLayer:mainLayer];
      [self setWantsLayer:YES];
    }

    return self;
    }

    Then, the custom NSView declares a drawLayer method as such (that I'd
    want to be called from my mainLayer):

    -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    {
    NSLog (@"Entered drawLayer");
    }

    Now, whenever I send the setNeedsDisplay message to mainLayer, I
    assume that drawLayer would be called. It is not.

    drawLayer is also declared in the .h for the custom NSView (if that
    makes any difference).

    If I override and define drawRect for my NSView, I can verify that it
    does enter that method:

    - (void)drawRect:(NSRect)rect
    {
    NSLog (@"Entered drawRect");
    }

    What am I doing wrong?
  • You could try creating your own CALayer derived class that overrides

    - (void)drawInContext:(CGContextRef)ctx

    drawLayer simply allows your delegate to override that same method
    externally.

    -Matt

    On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:

    > Hello everyone,
    >
    > I'm a very new cocoa developer (I switched two months ago) but an
    > experienced (15+ years) developer.
    >
    > I'm struggling trying to get a CALayer delegate method, specifically
    > drawLayer being called. I am trying to host the CALayer inside an
    > NSView that would be the delegate for the CALayer.
    >
    > The CALayer is an attribute of my custom NSView called mainLayer.
    >
    > Here is the initWithFrame method for my custom NSView:
    >
    > -(id) initWithFrame: (NSRect) frameRect
    > {
    > self = [super initWithFrame:frameRect];
    >
    > if (self)
    > {
    > mainLayer = [[[CALayer alloc] init] retain];
    >
    > [mainLayer setDelegate:self];
    > [self setLayer:mainLayer];
    > [self setWantsLayer:YES];
    > }
    >
    > return self;
    > }
    >
    > Then, the custom NSView declares a drawLayer method as such (that
    > I'd want to be called from my mainLayer):
    >
    > -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    > {
    > NSLog (@"Entered drawLayer");
    > }
    >
    > Now, whenever I send the setNeedsDisplay message to mainLayer, I
    > assume that drawLayer would be called. It is not.
    >
    > drawLayer is also declared in the .h for the custom NSView (if that
    > makes any difference).
    >
    > If I override and define drawRect for my NSView, I can verify that
    > it does enter that method:
    >
    > - (void)drawRect:(NSRect)rect
    > {
    > NSLog (@"Entered drawRect");
    > }
    >
    >
    > What am I doing wrong?
  • sure, but I don't really want to subclass calayer (unnecessary) and I
    have a feeling I would run into the same problem, no?

    On 23-Feb-08, at 12:20 AM, Matt Long wrote:

    > You could try creating your own CALayer derived class that overrides
    >
    > - (void)drawInContext:(CGContextRef)ctx
    >
    > drawLayer simply allows your delegate to override that same method
    > externally.
    >
    > -Matt
    >
    >
    > On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >
    >> Hello everyone,
    >>
    >> I'm a very new cocoa developer (I switched two months ago) but an
    >> experienced (15+ years) developer.
    >>
    >> I'm struggling trying to get a CALayer delegate method,
    >> specifically drawLayer being called. I am trying to host the
    >> CALayer inside an NSView that would be the delegate for the CALayer.
    >>
    >> The CALayer is an attribute of my custom NSView called mainLayer.
    >>
    >> Here is the initWithFrame method for my custom NSView:
    >>
    >> -(id) initWithFrame: (NSRect) frameRect
    >> {
    >> self = [super initWithFrame:frameRect];
    >>
    >> if (self)
    >> {
    >> mainLayer = [[[CALayer alloc] init] retain];
    >>
    >> [mainLayer setDelegate:self];
    >> [self setLayer:mainLayer];
    >> [self setWantsLayer:YES];
    >> }
    >>
    >> return self;
    >> }
    >>
    >> Then, the custom NSView declares a drawLayer method as such (that
    >> I'd want to be called from my mainLayer):
    >>
    >> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >> {
    >> NSLog (@"Entered drawLayer");
    >> }
    >>
    >> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >> assume that drawLayer would be called. It is not.
    >>
    >> drawLayer is also declared in the .h for the custom NSView (if that
    >> makes any difference).
    >>
    >> If I override and define drawRect for my NSView, I can verify that
    >> it does enter that method:
    >>
    >> - (void)drawRect:(NSRect)rect
    >> {
    >> NSLog (@"Entered drawRect");
    >> }
    >>
    >>
    >> What am I doing wrong?
    >
  • Instead of creating CALayer object using,
    mainLayer = [[[CALayer alloc] init] retain];

    try creating the CALayer this way,
    mainLayer = [[CALayer layer] retain];

    -Vinay

    On Feb 23, 2008, at 10:50 AM, Matt Long wrote:

    > You could try creating your own CALayer derived class that overrides
    >
    > - (void)drawInContext:(CGContextRef)ctx
    >
    > drawLayer simply allows your delegate to override that same method
    > externally.
    >
    > -Matt
    >
    >
    > On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >
    >> Hello everyone,
    >>
    >> I'm a very new cocoa developer (I switched two months ago) but an
    >> experienced (15+ years) developer.
    >>
    >> I'm struggling trying to get a CALayer delegate method,
    >> specifically drawLayer being called. I am trying to host the
    >> CALayer inside an NSView that would be the delegate for the CALayer.
    >>
    >> The CALayer is an attribute of my custom NSView called mainLayer.
    >>
    >> Here is the initWithFrame method for my custom NSView:
    >>
    >> -(id) initWithFrame: (NSRect) frameRect
    >> {
    >> self = [super initWithFrame:frameRect];
    >>
    >> if (self)
    >> {
    >> mainLayer = [[[CALayer alloc] init] retain];
    >>
    >> [mainLayer setDelegate:self];
    >> [self setLayer:mainLayer];
    >> [self setWantsLayer:YES];
    >> }
    >>
    >> return self;
    >> }
    >>
    >> Then, the custom NSView declares a drawLayer method as such (that
    >> I'd want to be called from my mainLayer):
    >>
    >> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >> {
    >> NSLog (@"Entered drawLayer");
    >> }
    >>
    >> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >> assume that drawLayer would be called. It is not.
    >>
    >> drawLayer is also declared in the .h for the custom NSView (if that
    >> makes any difference).
    >>
    >> If I override and define drawRect for my NSView, I can verify that
    >> it does enter that method:
    >>
    >> - (void)drawRect:(NSRect)rect
    >> {
    >> NSLog (@"Entered drawRect");
    >> }
    >>
    >>
    >> What am I doing wrong?

    >
  • thanks, but this did not help. I'm still not getting drawLayer:
    inContext to be called.

    On 23-Feb-08, at 12:41 AM, Vinay Prabhu wrote:

    > Instead of creating CALayer object using,
    > mainLayer = [[[CALayer alloc] init] retain];
    >
    > try creating the CALayer this way,
    > mainLayer = [[CALayer layer] retain];
    >
    > -Vinay
    >
    > On Feb 23, 2008, at 10:50 AM, Matt Long wrote:
    >
    >> You could try creating your own CALayer derived class that overrides
    >>
    >> - (void)drawInContext:(CGContextRef)ctx
    >>
    >> drawLayer simply allows your delegate to override that same method
    >> externally.
    >>
    >> -Matt
    >>
    >>
    >> On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >>
    >>> Hello everyone,
    >>>
    >>> I'm a very new cocoa developer (I switched two months ago) but an
    >>> experienced (15+ years) developer.
    >>>
    >>> I'm struggling trying to get a CALayer delegate method,
    >>> specifically drawLayer being called. I am trying to host the
    >>> CALayer inside an NSView that would be the delegate for the CALayer.
    >>>
    >>> The CALayer is an attribute of my custom NSView called mainLayer.
    >>>
    >>> Here is the initWithFrame method for my custom NSView:
    >>>
    >>> -(id) initWithFrame: (NSRect) frameRect
    >>> {
    >>> self = [super initWithFrame:frameRect];
    >>>
    >>> if (self)
    >>> {
    >>> mainLayer = [[[CALayer alloc] init] retain];
    >>>
    >>> [mainLayer setDelegate:self];
    >>> [self setLayer:mainLayer];
    >>> [self setWantsLayer:YES];
    >>> }
    >>>
    >>> return self;
    >>> }
    >>>
    >>> Then, the custom NSView declares a drawLayer method as such (that
    >>> I'd want to be called from my mainLayer):
    >>>
    >>> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >>> {
    >>> NSLog (@"Entered drawLayer");
    >>> }
    >>>
    >>> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >>> assume that drawLayer would be called. It is not.
    >>>
    >>> drawLayer is also declared in the .h for the custom NSView (if
    >>> that makes any difference).
    >>>
    >>> If I override and define drawRect for my NSView, I can verify that
    >>> it does enter that method:
    >>>
    >>> - (void)drawRect:(NSRect)rect
    >>> {
    >>> NSLog (@"Entered drawRect");
    >>> }
    >>>
    >>>
    >>> What am I doing wrong?

    >>
    >
  • Try calling [mainLayer setNeedsDisplay] or [mainLayer display].  You
    need to call one of those to get layers to update properly.

    On Feb 22, 2008, at 9:48 PM, Francois-Jean De Brienne wrote:

    > thanks, but this did not help. I'm still not getting drawLayer:
    > inContext to be called.
    >
    >
    >
    > On 23-Feb-08, at 12:41 AM, Vinay Prabhu wrote:
    >
    >> Instead of creating CALayer object using,
    >> mainLayer = [[[CALayer alloc] init] retain];
    >>
    >> try creating the CALayer this way,
    >> mainLayer = [[CALayer layer] retain];
    >>
    >> -Vinay
    >>
    >> On Feb 23, 2008, at 10:50 AM, Matt Long wrote:
    >>
    >>> You could try creating your own CALayer derived class that overrides
    >>>
    >>> - (void)drawInContext:(CGContextRef)ctx
    >>>
    >>> drawLayer simply allows your delegate to override that same method
    >>> externally.
    >>>
    >>> -Matt
    >>>
    >>>
    >>> On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >>>
    >>>> Hello everyone,
    >>>>
    >>>> I'm a very new cocoa developer (I switched two months ago) but an
    >>>> experienced (15+ years) developer.
    >>>>
    >>>> I'm struggling trying to get a CALayer delegate method,
    >>>> specifically drawLayer being called. I am trying to host the
    >>>> CALayer inside an NSView that would be the delegate for the
    >>>> CALayer.
    >>>>
    >>>> The CALayer is an attribute of my custom NSView called mainLayer.
    >>>>
    >>>> Here is the initWithFrame method for my custom NSView:
    >>>>
    >>>> -(id) initWithFrame: (NSRect) frameRect
    >>>> {
    >>>> self = [super initWithFrame:frameRect];
    >>>>
    >>>> if (self)
    >>>> {
    >>>> mainLayer = [[[CALayer alloc] init] retain];
    >>>>
    >>>> [mainLayer setDelegate:self];
    >>>> [self setLayer:mainLayer];
    >>>> [self setWantsLayer:YES];
    >>>> }
    >>>>
    >>>> return self;
    >>>> }
    >>>>
    >>>> Then, the custom NSView declares a drawLayer method as such (that
    >>>> I'd want to be called from my mainLayer):
    >>>>
    >>>> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >>>> {
    >>>> NSLog (@"Entered drawLayer");
    >>>> }
    >>>>
    >>>> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >>>> assume that drawLayer would be called. It is not.
    >>>>
    >>>> drawLayer is also declared in the .h for the custom NSView (if
    >>>> that makes any difference).
    >>>>
    >>>> If I override and define drawRect for my NSView, I can verify
    >>>> that it does enter that method:
    >>>>
    >>>> - (void)drawRect:(NSRect)rect
    >>>> {
    >>>> NSLog (@"Entered drawRect");
    >>>> }
    >>>>
    >>>>
    >>>> What am I doing wrong?

    >>>
    >>

  • I am calling those methods but my drawLayer method still is not
    getting called.

    On 23-Feb-08, at 1:01 AM, Bob Van Osten wrote:

    > Try calling [mainLayer setNeedsDisplay] or [mainLayer display].  You
    > need to call one of those to get layers to update properly.
    >
    > On Feb 22, 2008, at 9:48 PM, Francois-Jean De Brienne wrote:
    >
    >> thanks, but this did not help. I'm still not getting drawLayer:
    >> inContext to be called.
    >>
    >>
    >>
    >> On 23-Feb-08, at 12:41 AM, Vinay Prabhu wrote:
    >>
    >>> Instead of creating CALayer object using,
    >>> mainLayer = [[[CALayer alloc] init] retain];
    >>>
    >>> try creating the CALayer this way,
    >>> mainLayer = [[CALayer layer] retain];
    >>>
    >>> -Vinay
    >>>
    >>> On Feb 23, 2008, at 10:50 AM, Matt Long wrote:
    >>>
    >>>> You could try creating your own CALayer derived class that
    >>>> overrides
    >>>>
    >>>> - (void)drawInContext:(CGContextRef)ctx
    >>>>
    >>>> drawLayer simply allows your delegate to override that same
    >>>> method externally.
    >>>>
    >>>> -Matt
    >>>>
    >>>>
    >>>> On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >>>>
    >>>>> Hello everyone,
    >>>>>
    >>>>> I'm a very new cocoa developer (I switched two months ago) but
    >>>>> an experienced (15+ years) developer.
    >>>>>
    >>>>> I'm struggling trying to get a CALayer delegate method,
    >>>>> specifically drawLayer being called. I am trying to host the
    >>>>> CALayer inside an NSView that would be the delegate for the
    >>>>> CALayer.
    >>>>>
    >>>>> The CALayer is an attribute of my custom NSView called mainLayer.
    >>>>>
    >>>>> Here is the initWithFrame method for my custom NSView:
    >>>>>
    >>>>> -(id) initWithFrame: (NSRect) frameRect
    >>>>> {
    >>>>> self = [super initWithFrame:frameRect];
    >>>>>
    >>>>> if (self)
    >>>>> {
    >>>>> mainLayer = [[[CALayer alloc] init] retain];
    >>>>>
    >>>>> [mainLayer setDelegate:self];
    >>>>> [self setLayer:mainLayer];
    >>>>> [self setWantsLayer:YES];
    >>>>> }
    >>>>>
    >>>>> return self;
    >>>>> }
    >>>>>
    >>>>> Then, the custom NSView declares a drawLayer method as such
    >>>>> (that I'd want to be called from my mainLayer):
    >>>>>
    >>>>> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >>>>> {
    >>>>> NSLog (@"Entered drawLayer");
    >>>>> }
    >>>>>
    >>>>> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >>>>> assume that drawLayer would be called. It is not.
    >>>>>
    >>>>> drawLayer is also declared in the .h for the custom NSView (if
    >>>>> that makes any difference).
    >>>>>
    >>>>> If I override and define drawRect for my NSView, I can verify
    >>>>> that it does enter that method:
    >>>>>
    >>>>> - (void)drawRect:(NSRect)rect
    >>>>> {
    >>>>> NSLog (@"Entered drawRect");
    >>>>> }
    >>>>>
    >>>>>
    >>>>> What am I doing wrong?

    >>>>
    >>>

    >
  • your code looks fine to me, ideally the delegates should get called.

    In my code, I have called the API's,
    self setLayer:mainLayer];
    [self setWantsLayer:YES];

    after the view is initialized, like,
    Code in the Controller class:
    CustomView* view = [[CustomView alloc] initWithFrame:rect];
    [view setUpCALayers];

    Code in the view class:
    - (void) setUpCALayers
    {
    self setLayer:mainLayer];
    [self setWantsLayer:YES];
    }
    - (void)updateLayers
    {
    [mainLayer setNeedsDisplay];
    }

    and it is perfectly working fine.
    I am not able to explain why delegates are not getting called in your
    code,
    but you can try moving the setLayer and setWantsLayer outside the init.

    -Vinay

    On Feb 23, 2008, at 11:18 AM, Francois-Jean De Brienne wrote:

    > thanks, but this did not help. I'm still not getting drawLayer:
    > inContext to be called.
    >
    >
    >
    > On 23-Feb-08, at 12:41 AM, Vinay Prabhu wrote:
    >
    >> Instead of creating CALayer object using,
    >> mainLayer = [[[CALayer alloc] init] retain];
    >>
    >> try creating the CALayer this way,
    >> mainLayer = [[CALayer layer] retain];
    >>
    >> -Vinay
    >>
    >> On Feb 23, 2008, at 10:50 AM, Matt Long wrote:
    >>
    >>> You could try creating your own CALayer derived class that overrides
    >>>
    >>> - (void)drawInContext:(CGContextRef)ctx
    >>>
    >>> drawLayer simply allows your delegate to override that same method
    >>> externally.
    >>>
    >>> -Matt
    >>>
    >>>
    >>> On Feb 22, 2008, at 9:52 PM, Francois-Jean De Brienne wrote:
    >>>
    >>>> Hello everyone,
    >>>>
    >>>> I'm a very new cocoa developer (I switched two months ago) but an
    >>>> experienced (15+ years) developer.
    >>>>
    >>>> I'm struggling trying to get a CALayer delegate method,
    >>>> specifically drawLayer being called. I am trying to host the
    >>>> CALayer inside an NSView that would be the delegate for the
    >>>> CALayer.
    >>>>
    >>>> The CALayer is an attribute of my custom NSView called mainLayer.
    >>>>
    >>>> Here is the initWithFrame method for my custom NSView:
    >>>>
    >>>> -(id) initWithFrame: (NSRect) frameRect
    >>>> {
    >>>> self = [super initWithFrame:frameRect];
    >>>>
    >>>> if (self)
    >>>> {
    >>>> mainLayer = [[[CALayer alloc] init] retain];
    >>>>
    >>>> [mainLayer setDelegate:self];
    >>>> [self setLayer:mainLayer];
    >>>> [self setWantsLayer:YES];
    >>>> }
    >>>>
    >>>> return self;
    >>>> }
    >>>>
    >>>> Then, the custom NSView declares a drawLayer method as such (that
    >>>> I'd want to be called from my mainLayer):
    >>>>
    >>>> -(void)drawLayer:(CALayer*) layer inContext:(CGContextRef)ctx
    >>>> {
    >>>> NSLog (@"Entered drawLayer");
    >>>> }
    >>>>
    >>>> Now, whenever I send the setNeedsDisplay message to mainLayer, I
    >>>> assume that drawLayer would be called. It is not.
    >>>>
    >>>> drawLayer is also declared in the .h for the custom NSView (if
    >>>> that makes any difference).
    >>>>
    >>>> If I override and define drawRect for my NSView, I can verify
    >>>> that it does enter that method:
    >>>>
    >>>> - (void)drawRect:(NSRect)rect
    >>>> {
    >>>> NSLog (@"Entered drawRect");
    >>>> }
    >>>>
    >>>>
    >>>> What am I doing wrong?

    >>>
    >>
    >
    >
  • On Fri, Feb 22, 2008 at 11:52 PM, Francois-Jean De Brienne
    <francois.debrienne...> wrote:
    > Here is the initWithFrame method for my custom NSView:

    Please see http://lists.apple.com/archives/cocoa-dev/2008/Feb/msg01837.html

    --Kyle Sluder
  • Thanks alot, kyle, that does it. Initializing my layer in the
    awakeFromNib method, my delegate does get called.

    But why?

    On 23-Feb-08, at 1:38 AM, Kyle Sluder wrote:

    > On Fri, Feb 22, 2008 at 11:52 PM, Francois-Jean De Brienne
    > <francois.debrienne...> wrote:
    >> Here is the initWithFrame method for my custom NSView:
    >
    > Please see http://lists.apple.com/archives/cocoa-dev/2008/Feb/msg01837.html
    >
    > --Kyle Sluder
  • On Sat, Feb 23, 2008 at 2:02 AM, Francois-Jean De Brienne
    <francois.debrienne...> wrote:
    > Thanks alot, kyle, that does it. Initializing my layer in the
    > awakeFromNib method, my delegate does get called.
    >
    > But why?

    The post I linked you to explains it all; when AppKit loads your nib,
    it creates the layer for you, but only after your -initWithFrame: has
    been called.  So any layer you create and set in -initWithFrame: is
    going to be wiped out in between initialization and -awakeFromNib.

    --Kyle Sluder