views:

116

answers:

2

If I implement the CALayer delegate method actionForLayer:forKey I can return [NSNull null] to force the CALayer to not animate any changes. Unfortunately, [NSNull null] doesn't implement the CAAction delegate and XCode kicks out the following warning:

warning: class 'NSNull' does not implement the 'CAAction' protocol

Here is the method code:

- (id<CAAction>)actionForLayer:(CALayer *)theLayer
                        forKey:(NSString *)theKey {
 //This disables the animations when moving things around
 //Also, don't animate the selection box. It was doing weird things
 if(undoGroupStarted || theLayer == self.selectionBox) {
  return [NSNull null];
 } else {
  return nil;
 }
}

Am I doing something wrong? Is returning [NSNull null] bad behavior? If so, what is another way to do what I am trying to do here? If not, how do I make the compiler happy?

A: 

Judging by Apple's CAAction documentation, the only built-in class that implements the CAAction protocol is CAAnimation (and its subclasses, of course). The compiler is expecting a return value that implements CAAction, so yes, returning [NSNull null] will not work. Do you really need to use this delegate method, as opposed to removing animations from the layer using [layer removeAllAnimations] or [layer removeAnimationForKey:]?

It seems wasteful, but if you absolutely have to use the delegate method, perhaps you could return a "blank" animation object:

return [CAAnimation animation];

Also, do you need to disable this animation permanently, or only in specific circumstances? If you don't need to permanently override the animation, you can use a CATransaction to disable animation for individual method calls, as documented here in the Core Animation Programming Guide.

Endemic
I only need to disable the animation under specific circumstances and the disable will behave the exact same way to a dozen or so layers. Using the delegate allows me to switch their behavior when the circumstances appear. I will try the blank animation to see if it works. I don't think the CATransaction will work but I will look at it again.
MrHen
+1  A: 

The "CoreAnimation Programming Guide" section Defined Search Pattern for Action Keys addresses this. They CALayer delegate can return nil to specify that it doesn't handle the action, but that the search should continue. It can also return [NSNull null] to specify that the action should not be handled (that is, the search should stop).

In the CALayer header, you'll see a bit more detail about how this is handled:

If any of these steps results in a non-nil action object, the following steps are ignored. If the final result is an instance of NSNull, it is converted to `nil'.

To make the compiler accept this, you can simply cast:

return (id <CAAction>)[NSNull null]; // Prevent the action from animating
tjw
Yeah, that got rid of the compiler warning. Something makes me pause at casting NSNull... but it obviously isn't going to cause any problems since I have been returning NSNull this whole time without an issue. Thanks.
MrHen