Nullable properties in subclasses of CALAyer

I defined a subclass of CALayer with an animation property, as discussed here . Now I would like to add one more (non-inactive) property for this level in order to support its internal accounting.

I set the value of the new property in drawInContext: but I find that it always reset is 0 on the next call. Is it because Core Animation assumes that this property also applies to animation and that it β€œanimates” its value with a constant 0, devoid of additional instructions? In any case, how can I add really non-active properties to subclasses of CALayer ?

I found a preliminary workaround using the global CGFloat _property instead of the @property (assign) CGFloat property , but would prefer to use the standard property syntax.

UPDATE 1

This is how I try to define a property in MyLayer.m :

 @interface MyLayer() @property (assign) CGFloat property; @end 

And this is how I assign it a value at the end of drawInContext: ::

 self.property = nonZero; 

For example, read the property at the beginning of drawInContext: like this:

 NSLog(@"property=%f", self.property); 

UPDATE 2

Perhaps this caused the problem (code inherited from this sample)?

 - (id)actionForKey:(NSString *) aKey { if ([aKey isEqualToString:@"someAnimatableProperty"]) { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:aKey]; animation.fromValue = [self.presentationLayer valueForKey:aKey]; return animation; } return [super actionForKey:aKey]; // also applies to my "property" } 
+2
source share
1 answer

To access the standard properties inside the drawing method, you need to make a few changes during the animation.

Use initializer

When CoreAnimation performs your animation, it creates shadow copies of your layer, and each copy will be displayed in a different frame. To create such copies, it calls -initWithLayer: From the Apple Documentation :

If you implement user-level subclasses, you can override this method and use it to copy the values ​​of instance variables to a new object. Subclasses should always refer to the implementation of the superclass.

Therefore, you need to implement -initWithLayer: and use it to manually copy the value of your property to a new instance, for example:

 - (id)initWithLayer:(id)layer { if ((self = [super initWithLayer:layer])) { // Check if it the right class before casting if ([layer isKindOfClass:[MyCustomLayer class]]) { // Copy the value of "myProperty" over from the other layer self.myProperty = ((MyCustomLayer *)layer).myProperty; } } return self; } 

Model layer access properties

A copy, in any case, takes place before the animation starts: you can see this by adding the NSLog call to -initWithLayer: As far as CoreAnimation knows, your property will always be zero. Moreover, the created copies are readonly, if you try to set self.myProperty from -drawInContext: when the method is called in one of the presentation copies, you get an exception:

 *** Terminating app due to uncaught exception 'CALayerReadOnly', reason: 'attempting to modify read-only layer <MyLayer: 0x8e94010>' *** 

Instead of setting self.myProperty you should write

 self.modelLayer.myProperty = 42.0f 

since modelLayer instead refers to the original instance of MyCustomLayer , and all copies of the presentation use the same model. Note that you should also do this when reading a variable, and not just when setting it. For completeness, you must also specify the presentationLayer property, which instead displays the current (copy) layer.

+8
source

All Articles