CABasicAnimation resets to initial value after animation completes
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
CABasicAnimation often appears to "reset" a layer when the animation ends, but that behavior is expected. Core Animation animates the presentation layer for display, while the model layer remains unchanged unless you update it yourself.
Why the Layer Snaps Back
A CALayer effectively has two relevant states during animation:
- the model layer, which stores the real property values
- the presentation layer, which shows the in-flight animated values on screen
When you add a CABasicAnimation, Core Animation interpolates the presentation layer from the start value to the end value. If you never change the model layer, the animation finishes, the presentation layer disappears, and the layer redraws using the original model value. That is the "reset."
This means the reset is not a bug in CABasicAnimation. It is a signal that the visual animation and the persistent state were never synchronized.
The Correct Fix: Update the Model Layer Too
The usual fix is simple: set the final value on the layer and add an animation that visually transitions to that value.
The important line is the assignment to boxView.layer.position. That updates the model layer, so when the animation ends the persistent state already matches the final frame.
This pattern is equally useful for opacity, bounds, transform, and other animatable layer properties.
Animating From the Current Visual State
If a new animation can start while a previous one is still running, you should often read the current value from the presentation layer. Otherwise, the next animation may jump because it starts from the stale model value instead of the current on-screen value.
Using presentation() is especially helpful for draggable views, interruptible animations, or repeated taps on the same control.
Why fillMode and isRemovedOnCompletion Are Usually the Wrong Fix
Many examples on the internet recommend this combination:
That can keep the last rendered frame visible, but it does not update the model layer. The screen may look correct for a moment while the actual state remains wrong underneath. This becomes fragile when the layer is later resized, reanimated, or queried by other code.
In other words, those properties change how the presentation layer is kept around; they do not make the final value real. They are better treated as special-purpose tools, not the default answer to persistence.
Using a Transaction Completion Block
If you need to do follow-up work after the animation ends, wrap the update in a CATransaction and attach a completion block.
This keeps the animation lifecycle explicit without relying on presentation-layer tricks as your source of truth.
Common Pitfalls
The most common mistake is adding a CABasicAnimation and assuming it mutates the real property on the layer. It does not; it only animates the displayed transition.
Another mistake is using fillMode = .forwards with isRemovedOnCompletion = false as a permanent fix. That can hide the symptom while leaving the underlying model value unchanged.
Developers also run into jumps when starting a new animation from the model value while a previous animation is still in flight. Reading from presentation() avoids that discontinuity.
Finally, if Auto Layout or view controller code later reassigns the view's frame or transform, it can override layer changes. When animating view-backed layers, make sure the rest of the layout system agrees with the final state you want.
Summary
- '
CABasicAnimationanimates the presentation layer, not the persistent model layer.' - Set the final layer property yourself if you want the end state to stick.
- Use
presentation()when a new animation should start from the current on-screen value. - Treat
fillModeandisRemovedOnCompletionas specialized tools, not the primary fix. - Keep view layout and layer state synchronized so later updates do not undo the animation result.

