Is there a way to observe changes in derived properties? For example, I want to know when a CALayer has been added as a sublayer so that I can adjust its geometry relative to its (new) parent.
So, I have a subclassed CALayer, say CustomLayer, and I figured I could register an observer for the property in init:
[self addObserver:self forKeyPath:@"superlayer" options:0 context:nil]
and implement observeValueForKeyPath:ofObject:change:context
. Nothing ever happens because, presumably, superlayer is a derived property (the attr dictionary stores an opaque ID for the parent). Similarly, I can't subclass setSuperlayer:
because it is never called. In fact, as far as I can tell there are no instance methods called or public properties set on the sublayer when a parent does [self addSublayer:aCustomLayer]
.
Then I thought, OK, I'll subclass addSublayer like this:
- (void)addSublayer:(CALayer *)aLayer {
[aLayer willChangeValueForKey:@"superlayer"];
[super addSublayer:aLayer];
[aLayer didChangeValueForKey:@"superlayer"];
}
but still nothing! (Perhaps it's a clue that when I make a simple standalone test class and use the will[did]ChangeValueForKey:
then it works.) This is maybe a more general Cocoa KVO question. What should I be doing? Thanks in advance!
-
[self addObserver:self forKeyPath:@"superlayer" options:0 context:nil]
Don't observe yourself through KVO. Change your accessors instead.
Similarly, I can't subclass setSuperlayer: because it is never called.
I take it you tried this and added NSLog and found that it wasn't called?
Then I thought, OK, I'll subclass addSublayer like this:
- (void)addSublayer:(CALayer *)aLayer { [aLayer willChangeValueForKey:@"superlayer"]; [super addSublayer:aLayer]; [aLayer didChangeValueForKey:@"superlayer"]; }
And the parent layer is also a CustomLayer, right? If the parent layer is a plain CALayer, anything you do in CustomLayer will have no effect.
dk : Re "don't observe yourself through KVO", in this case the property is derived so I can't change its accessor to trap the change. Re the 2nd part of the question: yes the parent layer is also a custom CA subclass. That's called. But the KVO notice isn't called. Weird. -
Well,
superlayer
is defined as areadonly
property, which means that there's nosetSuperlayer:
method. (If there is, it would be private, and you probably shouldn't use it.) If I had to make a guess, it would be that thesuperlayer
property just isn't KVO-compliant. And, aside from that, I generally don't think it's a good idea for classes to observe themselves.Maybe there's another way of doing this. When a layer is added to a superlayer, the
onOrderIn
action takes place. Now,actionForKey:
is an instance method that gives a layer an opportunity to customize the default animations for certain properties. You could overrideactionForKey:
to detect when theonOrderIn
action takes place, do your thing, then callsuper
's implementation.I consider this a pretty messy hack, too, though. But it should be a bit more "self-contained" than having to use custom layers for everything and messing with KVO messages.
dk : Ooh. I like the kCAOnOrderIn idea. Thanks for the tip. Will try. At least now I know from the 2 comments so far that I'm not doing something terribly wrong, but just struggling with the lack of completeness in an API implementation.
0 comments:
Post a Comment