Skip to content

Commit

Permalink
fix(animation): Fixed a problematic case where a native animation can…
Browse files Browse the repository at this point in the history
… be 'lost' if the GC is run during the duration of the animation, preventing the animation from being removed and leaving the UI in an undetermined undesired state.
  • Loading branch information
carldebilly committed Oct 5, 2021
1 parent 68f1f7d commit 81547ef
Showing 1 changed file with 21 additions and 10 deletions.
31 changes: 21 additions & 10 deletions src/Uno.UWP/UI/Composition/CoreAnimation.iOSmacOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal class UnoCoreAnimation : IDisposable

private static int _id = 0;

private readonly WeakReference<CALayer> _layer;
private readonly CALayer _layer;
private readonly string _property;
private readonly string _key;
private readonly float _from;
Expand Down Expand Up @@ -74,7 +74,7 @@ public UnoCoreAnimation(
Action? prepare = null,
Action? cleanup = null)
{
_layer = new WeakReference<CALayer>(layer);
_layer = layer;
_property = property;
_key = property + Interlocked.Increment(ref _id).ToStringInvariant();
_from = from;
Expand Down Expand Up @@ -133,15 +133,16 @@ public void Resume()

public void Cancel()
{
if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("CoreAnimation '{0}': animation cancelled (.Cancel).", _key);
}
StopAnimation(StopReason.Canceled);
}

private void StartAnimation(float from, float to, float delayMilliseconds, float durationMilliseconds)
{
if (!_layer.TryGetTarget(out var layer))
{
return;
}
var layer = _layer;

if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
Expand Down Expand Up @@ -191,11 +192,17 @@ private void StartAnimation(float from, float to, float delayMilliseconds, float

private void StopAnimation(StopReason reason, long? time = default, float? value = default)
{
if (_current.animation == null || !_layer.TryGetTarget(out var layer))
if (_current.animation == null)
{
if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("CoreAnimation '{0}' unable to remove native animation: no running animation. Already disposed?", _key);
}
return;
}

var layer = _layer;

if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("CoreAnimation '{0}' is forcefully stopping.", _key);
Expand Down Expand Up @@ -259,18 +266,22 @@ void Handler(object? sender, CAAnimationStateEventArgs args)
var (currentAnim, from, to) = _current;
if (currentAnim != animation)
{
if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("CoreAnimation '{0}' [{1}]: unable to {2} because another animation is running.", _key, _property, _stop.reason);
}
return; // We are no longer the current animation, do not interfere with the current
}

_current = default;

if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().DebugFormat("CoreAnimation on property {0} has been {1}.", _property, _stop.reason);
this.Log().DebugFormat("CoreAnimation {0} has been {1}.", _key, _stop.reason);
}

// First commit the expected final (end, current or initial) value.
if (_layer.TryGetTarget(out var layer))
var layer = _layer;
{
var keyPath = new NSString(_property);
NSObject finalValue;
Expand Down Expand Up @@ -303,7 +314,7 @@ void Handler(object? sender, CAAnimationStateEventArgs args)

if (this.Log().IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
{
this.Log().Debug($"CoreAnimation Stopped (reason: {_stop.reason}, Finished:{args.Finished})");
this.Log().DebugFormat("CoreAnimation {0} [{1}] Stopped (reason: {2}, Finished:{3})", _key, _property, _stop.reason, args.Finished);
}

// Finally raise callbacks
Expand Down

0 comments on commit 81547ef

Please sign in to comment.