There are several different ways to achieve the result you need, but before looking at them, I must explain the root cause of the problem.
What's happening
What you see on the screen during the animation does not necessarily correspond to the property values of these layers. In fact, adding animations to a layer does not change the animated property of the layer. The animation and values that you see on the screen happen on a rendering server that runs in a different process than your application. You cannot get to these exact values, but you can get closer to the name of the values of the view. Since we cannot get to the values of the rendering server, we often talk only about the model values (the actual values of your layer object) and the values of the view (which appears on the screen (or at least very close to it)).
Only specifying toValue for CABasicAnimation means that it is animated from the current model value and the specified value. Please note that the documentation states that this is the current value of the view, but that is actually incorrect . Since the value of the model never changes, this means that when a second animation is added, it animates from the unchanged untreated value of the model to toValue .
(As a note: since two animations use the same key, the new one replaces the old one. This does not really matter, since the animations are not additive, so even if the animation has not been replaced, the new animation will write its value on top of the old animation value).
Various ways of fixing it
There are many ways to get the right behavior, starting with the simplest version.
Adding an explicit fromValue
As mentioned above, only with non-nil toValue animation start at the current model value. However, you can add non-nil fromValue , which is the current value of the view.
You can get presentation from presentationLayer level. From it you can get the current rotation angle using the same path that you are animating and a little KVC (key coding):
NSNumber *currentAngle = [switch.layer.presentationLayer valueForKeyPath:@"transform.rotation"];
If you only established that as fromValue animation you would get the correct initial value, but the rotation might not be 360 degrees more. While you can define the angle and create a new toValue , there is another byValue property that makes a relative change. Specifying byValue and fromValue (but not toValue) means:
Interpolates between fromValue and (fromValue + byValue) .
So you can change the animation code to:
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; fullRotation.fromValue = currentAngle;
At this point, your code should continue from the correct value, but the overall animation speed might look a little strange (it should have looked odd even before this code change). For a view that rotates continuously, you probably want it to always rotate at the same speed (as opposed to accelerating and decelerating for each rotation). You can get this by setting the animation to a linear synchronization function:
fullRotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
This should give you the behavior you need. Some stylistic notes are to specify either INFINITY or HUGE_VALF for counting repetitions, if you don't want it to rotate exactly 1000 times, and use a more descriptive key when adding a layer (unless you use the key for something else ( e.g. removing animation from a layer):
fullRotation.repeatCount = INFINITY; [stick.layer addAnimation:fullRotation forKey:@"rotate continuously"];
Layer speed change
I would think twice before using this as a solution in production code, but it can be interesting as a training exercise. Since what you mostly do slows down the animation, changing the duration from 4 seconds to 6 seconds, one thing you can do to create the same effect is to slow down the level. Note that this will have side effects (all animations on this layer and all of its sublayers will also be affected).
You cannot modify the animation after adding it to the layer, but the layer itself also conforms to the CAMediaTiming protocol, which means that it has the speed property. Setting the speed to 4.0/6.0 and saving the old animation on the layer will slow it down, making each rotation in 6 seconds instead of 4.
Once again, a bit hacked but fun as a training exercise.