diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml
new file mode 100644
index 00000000000..02cc8d6a058
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml.cs
new file mode 100644
index 00000000000..2ee8baf7cca
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue6742.xaml.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Runtime.CompilerServices;
+using System.ComponentModel;
+using System.Collections.Generic;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 6742, "Memory leak in ListView with uneven rows on IOS", PlatformAffected.Default)]
+ public partial class Issue6742 : TestContentPage
+ {
+ public Issue6742()
+ {
+#if APP
+ InitializeComponent();
+#endif
+ BindingContext = viewModel = new ViewModelIssue6742();
+
+ }
+ protected override void Init()
+ {
+
+ }
+ ViewModelIssue6742 viewModel;
+ IList> _weakList = new List>();
+ private void RefreshItems(object sender, EventArgs e)
+ {
+ foreach (var item in this.viewModel.ItemGroups)
+ {
+ item.Clear();
+ }
+ viewModel.ItemGroups.Clear();
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ CleanWeakList(_weakList);
+ viewModel.DisposeString = $"{_weakList.Count} object(s) alive";
+
+ string report = $"MEMORY:{GC.GetTotalMemory(true)}";
+ viewModel.TotalMemory = report;
+
+ var g1 = new ModelIssue6742Group("Group 1")
+ {
+ new ModelIssue6742("first", viewModel),
+ new ModelIssue6742("second", viewModel),
+ };
+
+ _weakList.Add(new WeakReference(g1[0]));
+ _weakList.Add(new WeakReference(g1[1]));
+
+ viewModel.ItemGroups.Add(g1);
+
+ var g2 = new ModelIssue6742Group("Group 2")
+ {
+ new ModelIssue6742("third", viewModel),
+ new ModelIssue6742("fourth", viewModel),
+ };
+
+ _weakList.Add(new WeakReference(g2[0]));
+ _weakList.Add(new WeakReference(g2[1]));
+
+ viewModel.ItemGroups.Add(g2);
+
+ var g3 = new ModelIssue6742Group("Group 3")
+ {
+ new ModelIssue6742("fifth", viewModel),
+ new ModelIssue6742("sixth", viewModel),
+ new ModelIssue6742("seventh", viewModel),
+ };
+
+ _weakList.Add(new WeakReference(g3[0]));
+ _weakList.Add(new WeakReference(g3[1]));
+ _weakList.Add(new WeakReference(g3[2]));
+
+ viewModel.ItemGroups.Add(g3);
+ }
+
+ private void CleanWeakList(IList> weakList)
+ {
+ ModelIssue6742 item;
+ for (int i = weakList.Count-1; i >= 0; i--)
+ {
+ if (!weakList[i].TryGetTarget(out item))
+ {
+ weakList.RemoveAt(i);
+ }
+ }
+ }
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ViewModelIssue6742 : INotifyPropertyChanged
+ {
+ public ObservableCollection ItemGroups { get; set; } = new ObservableCollection();
+ public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
+
+ private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new 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 ViewModelIssue6742()
+ {
+
+ }
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ModelIssue6742Group : ObservableCollection
+ {
+ public ModelIssue6742Group(string name)
+ {
+ GroupName = name;
+ }
+ public string GroupName { get; set; }
+
+ }
+
+ [Preserve(AllMembers = true)]
+ public class ModelIssue6742
+ {
+ ViewModelIssue6742 _model;
+
+ public ModelIssue6742(string name, ViewModelIssue6742 model)
+ {
+ _model = model;
+ 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 309f493248b..440df1dfe31 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
@@ -64,6 +64,9 @@
Issue11794.xaml
+
+ Issue6742.xaml
+
@@ -2665,6 +2668,10 @@
+
+ Designer
+ MSBuild:UpdateDesignTimeXaml
+
Designer
MSBuild:UpdateDesignTimeXaml
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs
index 79c528a506c..9e600a10773 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/ListViewRenderer.cs
@@ -858,6 +858,7 @@ nfloat GetEstimatedRowHeight(UITableView table)
var firstCell = templatedItems.ActivateContent(0, item);
+ nfloat returnValue;
// Let's skip this optimization for grouped lists. It will likely cause more trouble than it's worth.
if (firstCell?.Height > 0 && !isGroupingEnabled)
{
@@ -867,10 +868,15 @@ nfloat GetEstimatedRowHeight(UITableView table)
// In this case, we will cache the specified cell heights asynchronously, which will be returned one time on
// table load by EstimatedHeight.
- return 0;
+ returnValue= 0;
+ }
+ else
+ {
+ returnValue = CalculateHeightForCell(table, firstCell);
}
- return CalculateHeightForCell(table, firstCell);
+ TemplatedItemsView.UnhookContent(firstCell);
+ return returnValue;
}
internal override void InvalidatingPrototypicalCellCache()