From 247f758523c8bce9162b0a7192b24b53a9d4ae86 Mon Sep 17 00:00:00 2001
From: kicsiede <4233752+kicsiede@users.noreply.github.com>
Date: Wed, 8 May 2019 19:41:08 +0200
Subject: [PATCH] [iOS] Fix: memory leak when Navigation.RemovePage is used
(#5695)
* Fix: memoryleak when Navigation.RemovePage is used
The leak occurs in a MasterDetailPage.Detail = NavigationPage(ContentPage) scenario if the ContentPage has ToolBarItems. (ToolBarItems create a strong dependency therefore the ViewController of the NavigationPage must be explicitly disposed)
* + unit test
* fix issue attribute
---
.../Issue5695.cs | 96 ++++++++++++++++++++++
.../Xamarin.Forms.Controls.Issues.Shared.projitems | 1 +
.../Renderers/NavigationRenderer.cs | 1 +
3 files changed, 98 insertions(+)
create mode 100644 Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue5695.cs
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue5695.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue5695.cs
new file mode 100644
index 0000000..ae13a19
--- /dev/null
+++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue5695.cs
@@ -0,0 +1,96 @@
+using System;
+using System.Collections.Generic;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+
+#if UITEST
+using NUnit.Framework;
+using Xamarin.UITest;
+using Xamarin.Forms.Core.UITests;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+ [Preserve(AllMembers = true)]
+ [Issue(IssueTracker.Github, 5695, "Memory leak when Navigation.RemovePage", PlatformAffected.iOS)]
+ public class Issue5695 : TestMasterDetailPage
+ {
+ [Preserve(AllMembers = true)]
+ class LeakPage : ContentPage
+ {
+ public LeakPage()
+ {
+ ToolbarItems.Add(new ToolbarItem { Text = "Dummy" });
+ }
+ }
+
+ protected override void Init ()
+ {
+ var wref = new WeakReference(null);
+
+ var result = new Label {
+ FontSize = 16,
+ Text = "Click 'Push page'"
+ };
+
+ var checkResult = new Button
+ {
+ Text = "Check Result",
+ IsEnabled = false,
+ Command = new Command(() =>
+ {
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ result.Text = wref.IsAlive ? "Failed" : "Success";
+ })
+ };
+
+ Detail = new NavigationPage(new LeakPage());
+
+ Master = new ContentPage
+ {
+ Title = "menu",
+ Content = new StackLayout
+ {
+ Children = {
+ result,
+ new Button
+ {
+ Text = "Push page",
+ Command = new Command(async() => {
+
+ await Detail.Navigation.PushAsync(new LeakPage());
+
+ var pageToRemove = Detail.Navigation.NavigationStack[0];
+
+ Detail.Navigation.RemovePage(pageToRemove);
+
+ wref.Target = pageToRemove;
+
+ checkResult.IsEnabled = true;
+ result.Text = "You can check result";
+ })
+ },
+ checkResult
+ }
+ }
+ };
+ }
+
+#if UITEST
+ [Test]
+ public void Issue5695Test()
+ {
+ RunningApp.Tap(q => q.Marked("Push page"));
+ RunningApp.WaitForElement(q => q.Marked("Push page"));
+
+ RunningApp.WaitForElement(q => q.Marked("You can check result"));
+ RunningApp.Tap(q => q.Marked("Check Result"));
+
+ RunningApp.WaitForElement(q => q.Marked("Success"));
+ }
+#endif
+ }
+}
\ No newline at end of file
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 c134900..1ed6663 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
@@ -465,6 +465,7 @@
Issue5003.xaml
Code
+
diff --git a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs
index 3436edc..c38f4fc 100644
--- a/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs
+++ b/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs
@@ -587,6 +587,7 @@ namespace Xamarin.Forms.Platform.iOS
_removeControllers = _removeControllers.Remove(target);
ViewControllers = _removeControllers;
}
+ target.Dispose();
var parentingViewController = ViewControllers.Last() as ParentingViewController;
parentingViewController?.UpdateLeftBarButtonItem(page);
}
--
2.7.4