diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml
new file mode 100644
index 00000000000..59e9ea72231
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml.cs
new file mode 100644
index 00000000000..f39ccc542bd
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6761.xaml.cs
@@ -0,0 +1,142 @@
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System;
+using System.Collections.ObjectModel;
+using System.Runtime.CompilerServices;
+using System.ComponentModel;
+using System.Collections.Generic;
+
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 6761, "Memory leak in ListView with group headers on IOS", PlatformAffected.Default)]
+ public partial class Issue6761 : TestContentPage
+ {
+ public Issue6761()
+ {
+#if APP
+ InitializeComponent();
+#endif
+ BindingContext = _viewModel = new ViewModelIssue6761();
+
+ }
+
+ protected override void Init()
+ {
+ }
+
+ int _count;
+ ViewModelIssue6761 _viewModel;
+ IList> _weakList = new List>();
+ private void RefreshItems(object sender, EventArgs e)
+ {
+ foreach (var item in this._viewModel.ItemGroups)
+ {
+ item.Clear();
+ }
+ this._viewModel.ItemGroups.Clear();
+
+ for (int i = 0; i < 30; i++)
+ {
+ _count++;
+ var g1 = new ModelIssue6761Group("Group " + _count);
+ _weakList.Add(new WeakReference(g1));
+ this._viewModel.ItemGroups.Add(g1);
+ }
+
+ CleanAndReport();
+ }
+
+ private void GCClick(object sender, EventArgs e)
+ {
+ CleanAndReport();
+ }
+ void CleanAndReport()
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ CleanWeakList(_weakList);
+ _viewModel.DisposeString = $"{_weakList.Count} object(s) alive";
+
+ string report = $"MEMORY:{GC.GetTotalMemory(true)}";
+ _viewModel.TotalMemory = report;
+ }
+
+ private void CleanWeakList(IList> weakList)
+ {
+ ModelIssue6761Group item;
+ for (int i = weakList.Count-1; i >= 0; i--)
+ {
+ if (!weakList[i].TryGetTarget(out item))
+ {
+ weakList.RemoveAt(i);
+ }
+ }
+ }
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ViewModelIssue6761 : INotifyPropertyChanged
+ {
+ public ObservableCollection ItemGroups { get; set; } = new ObservableCollection();
+ public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
+
+ private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ this.PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
+ }
+
+
+ string _DisposeString;
+ public string DisposeString
+ {
+ get { return _DisposeString; }
+ set
+ {
+ _DisposeString = value;
+ NotifyPropertyChanged();
+ }
+ }
+
+ string _totalMemory;
+ public string TotalMemory
+ {
+ get => _totalMemory;
+ set
+ {
+ _totalMemory = value;
+ NotifyPropertyChanged();
+ }
+ }
+
+ public ViewModelIssue6761()
+ {
+
+ }
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ModelIssue6761Group : ObservableCollection
+ {
+ public ModelIssue6761Group(string name)
+ {
+ GroupName = name;
+ }
+ public string GroupName { get; set; }
+
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ModelIssue6761
+ {
+ public ModelIssue6761(string name)
+ {
+ Name = name;
+ }
+ public string Name { get; set; }
+
+ }
+}
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
index 00a3ffb9cd0..5577f4341f1 100644
--- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
@@ -92,6 +92,7 @@
Issue11794.xaml
+
Issue6742.xaml
@@ -1731,6 +1732,9 @@
Issue11081.xaml
+
+ Issue6761.xaml
+
@@ -1961,6 +1965,9 @@
MSBuild:UpdateDesignTimeXaml
+
+ MSBuild:UpdateDesignTimeXaml
+
Designer
diff --git a/Xamarin.Forms.Core/TemplatedItemsList.cs b/Xamarin.Forms.Core/TemplatedItemsList.cs
index 6facef478b1..cbff43ada8b 100644
--- a/Xamarin.Forms.Core/TemplatedItemsList.cs
+++ b/Xamarin.Forms.Core/TemplatedItemsList.cs
@@ -231,17 +231,16 @@ public void Dispose()
return;
_itemsView.PropertyChanged -= BindableOnPropertyChanged;
+ ListProxy.CollectionChanged -= OnProxyCollectionChanged;
TItem header = HeaderContent;
- if (header != null)
- UnhookItem(header);
-
- for (var i = 0; i < _templatedObjects.Count; i++)
+ if (header != null && header.BindingContext != null)
{
- TItem item = _templatedObjects[i];
- if (item != null)
- UnhookItem(item);
+ UnhookItem(header);
}
+
+ HeaderContent = null;
+ UnhookAndClear();
for (var i = 0; i < _groupedItems?.Count; i++)
{
@@ -716,7 +715,7 @@ void GroupedReset()
_groupedItems.Clear();
}
- _templatedObjects.Clear();
+ UnhookAndClear();
var i = 0;
foreach (object item in ListProxy)
@@ -821,6 +820,7 @@ void OnCollectionChangedGrouped(NotifyCollectionChangedEventArgs e)
til.CollectionChanged -= OnInnerCollectionChanged;
oldItems.Add(til);
_groupedItems.RemoveAt(index);
+ UnhookItem(_templatedObjects[index]);
_templatedObjects.RemoveAt(index);
til.Dispose();
}
@@ -845,6 +845,7 @@ void OnCollectionChangedGrouped(NotifyCollectionChangedEventArgs e)
oldItems.Add(til);
_groupedItems.RemoveAt(index);
+ UnhookItem(_templatedObjects[index]);
_templatedObjects.RemoveAt(index);
newItems.Add(InsertGrouped(e.NewItems[i], index));
diff --git a/Xamarin.Forms.Platform.iOS/Cells/CellTableViewCell.cs b/Xamarin.Forms.Platform.iOS/Cells/CellTableViewCell.cs
index 89f67cfaefd..0196275a090 100644
--- a/Xamarin.Forms.Platform.iOS/Cells/CellTableViewCell.cs
+++ b/Xamarin.Forms.Platform.iOS/Cells/CellTableViewCell.cs
@@ -8,7 +8,7 @@ public class CellTableViewCell : UITableViewCell, INativeElementView
{
Cell _cell;
- public Action