diff --git a/Xamarin.Forms.Core/Interactivity/AttachedCollection.cs b/Xamarin.Forms.Core/Interactivity/AttachedCollection.cs index e2f420bfce43..1acb7a15188d 100644 --- a/Xamarin.Forms.Core/Interactivity/AttachedCollection.cs +++ b/Xamarin.Forms.Core/Interactivity/AttachedCollection.cs @@ -8,6 +8,9 @@ internal class AttachedCollection : ObservableCollection, ICollection, { readonly List _associatedObjects = new List(); + const int CleanupTrigger = 128; + int _cleanupThreshold = CleanupTrigger; + public AttachedCollection() { } @@ -64,6 +67,7 @@ protected virtual void OnAttachedTo(BindableObject bindable) lock (_associatedObjects) { _associatedObjects.Add(new WeakReference(bindable)); + CleanUpWeakReferences(); } foreach (T item in this) item.AttachTo(bindable); @@ -123,5 +127,16 @@ protected override void SetItem(int index, T item) 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 diff --git a/Xamarin.Forms.Core/Style.cs b/Xamarin.Forms.Core/Style.cs index b6ee9112b07e..7adbc1e3e193 100644 --- a/Xamarin.Forms.Core/Style.cs +++ b/Xamarin.Forms.Core/Style.cs @@ -10,6 +10,9 @@ public sealed class Style : IStyle { 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 @@ void IStyle.Apply(BindableObject bindable) if (BaseResourceKey != null) bindable.SetDynamicResource(_basedOnResourceProperty, BaseResourceKey); ApplyCore(bindable, BasedOn ?? GetBasedOnResource(bindable)); + + CleanUpWeakReferences(); } public Type TargetType { get; } @@ -178,5 +183,16 @@ bool ValidateBasedOn(Style value) 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