Occasionally clean up WeakReferences in Styles whose targets have been collected...
authorE.Z. Hart <hartez@users.noreply.github.com>
Thu, 24 Oct 2019 17:47:05 +0000 (11:47 -0600)
committerSamantha Houts <samhouts@users.noreply.github.com>
Mon, 28 Oct 2019 23:40:14 +0000 (16:40 -0700)
Xamarin.Forms.Core/Interactivity/AttachedCollection.cs
Xamarin.Forms.Core/Style.cs

index e2f420b..1acb7a1 100644 (file)
@@ -8,6 +8,9 @@ namespace Xamarin.Forms
        {
                readonly List<WeakReference> _associatedObjects = new List<WeakReference>();
 
+               const int CleanupTrigger = 128;
+               int _cleanupThreshold = CleanupTrigger;
+
                public AttachedCollection()
                {
                }
@@ -64,6 +67,7 @@ namespace Xamarin.Forms
                        lock (_associatedObjects)
                        {
                                _associatedObjects.Add(new WeakReference(bindable));
+                               CleanUpWeakReferences();
                        }
                        foreach (T item in this)
                                item.AttachTo(bindable);
@@ -123,5 +127,16 @@ namespace Xamarin.Forms
                                item.AttachTo(bindable);
                        }
                }
+
+               void CleanUpWeakReferences()
+               {
+                       if (_associatedObjects.Count < _cleanupThreshold)
+                       {
+                               return;
+                       }
+
+                       _associatedObjects.RemoveAll(t => !t.IsAlive);
+                       _cleanupThreshold = _associatedObjects.Count + CleanupTrigger;
+               }
        }
 }
\ No newline at end of file
index b6ee911..7adbc1e 100644 (file)
@@ -10,6 +10,9 @@ namespace Xamarin.Forms
        {
                internal const string StyleClassPrefix = "Xamarin.Forms.StyleClass.";
 
+               const int CleanupTrigger = 128;
+               int _cleanupThreshold = CleanupTrigger;
+
                readonly BindableProperty _basedOnResourceProperty = BindableProperty.CreateAttached("BasedOnResource", typeof(Style), typeof(Style), default(Style),
                        propertyChanged: OnBasedOnResourceChanged);
 
@@ -93,6 +96,8 @@ namespace Xamarin.Forms
                        if (BaseResourceKey != null)
                                bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey);
                        ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable));
+
+                       CleanUpWeakReferences();
                }
 
                public Type TargetType { get; }
@@ -178,5 +183,16 @@ namespace Xamarin.Forms
                                return true;
                        return value.TargetType.IsAssignableFrom(TargetType);
                }
+
+               void CleanUpWeakReferences()
+               {
+                       if (_targets.Count < _cleanupThreshold)
+                       {
+                               return;
+                       }
+
+                       _targets.RemoveAll(t => !t.TryGetTarget(out _));
+                       _cleanupThreshold = _targets.Count + CleanupTrigger;
+               }
        }
 }
\ No newline at end of file