Gold Challenge solution and Question


See code below for solution. The question is, if I set the move CABAsicAnimation delegate to self and implement animationDidStop:finished: the animation object passed to the method is different than the move object pointer. How come? testing if(animo == move) is false and logging them reveals different pointer addresses. If the animation object passed to the delegate method is not the same as the one added to the layer, how are going to distinguish between different animation objects delegated on the same controller?

in TimeViewController.h

[code]@interface TimeViewController : UIViewController {
__weak IBOutlet UILabel *timeLabel;
__weak IBOutlet UIButton *timeButton;

CABasicAnimation *move;
CABasicAnimation *fade;


in TimeViewController.m

[super viewDidLoad];

// Make and configure move animation:
move = [CABasicAnimation animationWithKeyPath:@"transform"];
CATransform3D moveRight = CATransform3DMakeTranslation(-240, 0.0, 0.0);
CATransform3D identity = CATransform3DIdentity;
[move setFromValue:[NSValue valueWithCATransform3D:moveRight]];
[move setToValue:[NSValue valueWithCATransform3D]];
[move setDuration:0.2];
CAMediaTimingFunction *tf = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
[move setTimingFunction:tf];
[move setRemovedOnCompletion:YES];
[move setDelegate:self];

// Make and configure fade animation:
fade = [CABasicAnimation animationWithKeyPath:@"opacity"];
[fade setFromValue:[NSNumber numberWithFloat:1.0]];
[fade setToValue:[NSNumber numberWithFloat:0.0]];
[fade setDuration:1.0];
[fade setAutoreverses:YES];
[fade setRepeatCount:HUGE_VALF];


-(void)viewDidAppear:(BOOL)animated {
[[timeButton layer] addAnimation:move forKey:@“moveAnimation”];

-(void)animationDidStop:(CAAnimation*)anim finished:(BOOL)flag {
if(flag) {
[[timeButton layer] addAnimation:fade forKey:@“fadeAnimation”];


A reaaaaaally late reply on this one, but I was interested in this too. Here’s the relevant documentation, from “CALayer Class Reference” under addAnimation:forKey:: “Note that the object is copied by the render tree, not referenced.”

StackOverflow seems to imply that the normal way to do it is by taking advantage of setting a custom key/value pair on the animation when you create it. See: … p-delegate … top-method

That seems pretty good. For the record, the way I first did it was by setting [move setRemovedOnCompletion:NO] when I created it. Then, in animationDidStop:

  if (anim == [[timeButton layer] animationForKey:@"moveAnimation"]) {
    [[timeButton layer] removeAnimationForKey:@"moveAnimation"];

But I admit this seems ugly.


What I did is implemented setValueForKey for the animation like this:

The key is that when you trying to check for the CAAnimation itself inside the animationDidStop method it already finished so it returns Null. But if you ask valueForKey of this animation it gives you the right one, so here is what I asked in it:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
	if ([[anim valueForKey:@"buttonSliderAnim"] isEqual: @"sliderAnim"])
		animStopped = 1;
		[self faderAnimation];