diff --git a/src/Controls/src/Core/Compatibility/Handlers/FlyoutPage/iOS/PhoneFlyoutPageRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/FlyoutPage/iOS/PhoneFlyoutPageRenderer.cs index 8cf5c209b799..f91e71fa055c 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/FlyoutPage/iOS/PhoneFlyoutPageRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/FlyoutPage/iOS/PhoneFlyoutPageRenderer.cs @@ -17,7 +17,7 @@ public class PhoneFlyoutPageRenderer : UIViewController, IPlatformViewHandler { UIView _clickOffView; UIViewController _detailController; - VisualElement _element; + WeakReference _element; bool _disposed; UIViewController _flyoutController; @@ -75,7 +75,7 @@ bool Presented get { return _presented; } } - public VisualElement Element => _viewHandlerWrapper.Element ?? _element; + public VisualElement Element => _viewHandlerWrapper.Element ?? _element?.GetTargetOrDefault(); public event EventHandler ElementChanged; @@ -100,7 +100,7 @@ public void SetElement(VisualElement element) _clickOffView = new UIView(); _clickOffView.BackgroundColor = new Color(0, 0, 0, 0).ToPlatform(); _viewHandlerWrapper.SetVirtualView(element, OnElementChanged, false); - _element = element; + _element = new(element); if (_intialLayoutFinished) { @@ -269,9 +269,7 @@ protected override void Dispose(bool disposing) } EmptyContainers(); - - Page.SendDisappearing(); - + _element = null; _disposed = true; } diff --git a/src/Controls/tests/DeviceTests/Elements/FlyoutPage/FlyoutPageTests.cs b/src/Controls/tests/DeviceTests/Elements/FlyoutPage/FlyoutPageTests.cs index e4cca9f2a725..9f25a9736ece 100644 --- a/src/Controls/tests/DeviceTests/Elements/FlyoutPage/FlyoutPageTests.cs +++ b/src/Controls/tests/DeviceTests/Elements/FlyoutPage/FlyoutPageTests.cs @@ -252,6 +252,39 @@ await CreateHandlerAndAddToWindow(flyoutPage, async (handler) }); } + [Fact(DisplayName = "FlyoutPage as Modal Does Not Leak")] + public async Task DoesNotLeakAsModal() + { + SetupBuilder(); + + var references = new List(); + var launcherPage = new ContentPage(); + var window = new Window(launcherPage); + + await CreateHandlerAndAddToWindow(window, async handler => + { + var flyoutPage = new FlyoutPage + { + Flyout = new ContentPage + { + Title = "Flyout", + IconImageSource = "icon.png" + }, + Detail = new ContentPage { Title = "Detail" } + }; + + await launcherPage.Navigation.PushModalAsync(flyoutPage, true); + + references.Add(new WeakReference(flyoutPage)); + references.Add(new WeakReference(flyoutPage.Flyout)); + references.Add(new WeakReference(flyoutPage.Detail)); + + await launcherPage.Navigation.PopModalAsync(); + }); + + await AssertionExtensions.WaitForGC(references.ToArray()); + } + bool CanDeviceDoSplitMode(FlyoutPage page) { return ((IFlyoutPageController)page).ShouldShowSplitMode; diff --git a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla/Bugzilla31255.cs b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla/Bugzilla31255.cs index 6dae7258649e..ee76331c4ea4 100644 --- a/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla/Bugzilla31255.cs +++ b/src/Controls/tests/TestCases.HostApp/Issues/Bugzilla/Bugzilla31255.cs @@ -18,7 +18,8 @@ public MainPage() { VerticalOptions = LayoutOptions.Center, HorizontalTextAlignment = TextAlignment.Center, - Text = "Page 1" + Text = "Page 1", + AutomationId = "MauiLabel" }); Content = stack; @@ -60,12 +61,12 @@ public class Page2 : FlyoutPage { public Page2() { - Flyout = new Page() + Flyout = new ContentPage { Title = "Flyout", IconImageSource = "Icon.png" }; - Detail = new Page() { Title = "Detail" }; + Detail = new ContentPage() { Title = "Detail" }; } protected override async void OnAppearing() @@ -75,6 +76,10 @@ protected override async void OnAppearing() await Task.Delay(1000); await Navigation.PopModalAsync(); } + protected override void OnDisappearing() + { + base.OnDisappearing(); + } } } } diff --git a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla31255.cs b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla31255.cs index bf8d38f0cfbc..808b0470169b 100644 --- a/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla31255.cs +++ b/src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Bugzilla/Bugzilla31255.cs @@ -1,5 +1,4 @@ -#if IOS -using NUnit.Framework; +using NUnit.Framework; using UITest.Appium; using UITest.Core; @@ -14,15 +13,14 @@ public Bugzilla31255(TestDevice testDevice) : base(testDevice) public override string Issue => "Flyout's page Icon cause memory leak after FlyoutPage is popped out by holding on page"; [Test] - [Ignore("The sample is crashing. More information: https://github.com/dotnet/maui/issues/21206")] [Category(UITestCategories.Navigation)] [Category(UITestCategories.Compatibility)] - public async Task Bugzilla31255Test() + public void Bugzilla31255Test() { App.Screenshot("I am at Bugzilla 31255"); - await Task.Delay(5000); - App.WaitForNoElement("Page1. But Page2 IsAlive = False"); + Thread.Sleep(5000); + var text = App.WaitForElement("MauiLabel").GetText(); + Assert.That(text, Is.EqualTo("Page1. But Page2 IsAlive = False")); } } -} -#endif \ No newline at end of file +} \ No newline at end of file