tl; dr: It is very easy to abuse removeOnCompletion = NO , and most people do not understand the consequences of this. The correct decision is to change the value of the model "for real".
First of all: I am not trying to judge or be evil to you. I see the same misunderstanding over and over again, and I understand why this is happening. Explaining why everything happens, I hope that everyone who experiences the same problems and sees this answer will learn more about what their code does.
Something went wrong
I got the impression that animation.additive = YES; will cause further animations to use the current state as a starting point.
This is very true, and this is exactly what is happening. In this sense, computers are ridiculous. They are always exactly what you tell them, and not what you want to do from them.
removeOnCompletion = NO can be a bitch
In your case, the villain is a line of code:
animation.removedOnCompletion = NO;
It is often not recommended to use the final animation value after the animation is completed. The only problem is that this happens without removing the animation from the view. Animations in Core Animation do not change the underlying property that they animate, they simply animate it on the screen. If you look at the actual value during the animation, you will never see how this changes. Instead, the animation works on what is called the presentation layer.
Usually, when an animation finishes, it is removed from the layer, and the presentation layer disappears and the model layer reappears on the screen. However, when you save the animation attached to the layer, everything looks as it should on the screen, but you made the difference between what the property says is the transformation and how the layer rotates on the screen.
When you set up the animation as additive, it means that the from and to values are added to the existing value, as you said. The problem is that the value of this property is 0. You never change it, you just animate it. The next time you try to add this animation to the same layer, the value will still not be changed, but the animation does exactly what it has configured to execute: "animate additively from the current model value."
Decision
Skip this line of code. As a result, however, the rotation does not stick. The best way to do this is to change the model. Set a new final rotation value before the rotation animation so that the model looks as it should when the animation is deleted.
byValue is like magic
CABasicAnimation has a very convenient property (which I will use) called byValue , which can be used to create relative animations. It can be combined with toValue and fromValue to make many different kinds of animations. Various combinations are indicated in its documentation (in the section). The combination I'm going to use:
byValue and toValue are not nil . Interpolates between (toValue - byValue) and toValue .
Some actual code
With an explicit toValue of 0, the animation goes from "currentValue-byValue" to "current value". By changing the model, the first current value is the final value.
NSString *zRotationKeyPath = @"transform.rotation.z";
A small caveat :
I did not run this code, but I am pretty sure that it works as it should, and that I did not make any typos. Correct me if I do this. All discussion remains valid.