[iOS] Fix Shell page memory leak when using TitleView with x:Name#35082
[iOS] Fix Shell page memory leak when using TitleView with x:Name#35082kubaflo merged 6 commits intodotnet:inflight/currentfrom
Conversation
When Shell.TitleView is used together with x:Name, the page was not garbage collected on Windows. The MauiToolbar's ContentPresenter held a reference to the native TitleView, which through the MAUI handler chain referenced the TitleView VisualElement, whose NameScope entries pointed back to the page. Fix: in OnHandlerChanging (when the handler is set to null on navigation), disconnect the TitleView's handler and null out the native MauiToolbar TitleView reference to break the reference chain. Also updates the [Issue] attribute and test description to reflect that all three platforms (iOS, Android, Windows) are affected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35082Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35082" |
|
Hey there @@Shalini-Ashokan! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
Pull request overview
This PR addresses an iOS-specific Shell navigation memory leak where a Shell.TitleView combined with a page-level x:Name prevents the page from being garbage collected after navigating back.
Changes:
- Clear
UINavigationItem.TitleViewduringShellPageRendererTrackerdisposal on iOS to break the native retain chain. - Add a HostApp repro (
Issue34975+Issue34975SecondPage) that creates a weak-reference target and validates GC after a navigation round-trip. - Add an Appium UI test (
Issue34975) that drives the repro and asserts the leak is gone.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs | Clears the native NavigationItem.TitleView on disposal to allow managed page GC. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue34975.cs | Adds a Shell-based repro harness that navigates to a TitleView + x:Name page and checks GC. |
| src/Controls/tests/TestCases.HostApp/Issues/Issue34975SecondPage.xaml | Repro page using Shell.TitleView and x:Name (the leak trigger). |
| src/Controls/tests/TestCases.HostApp/Issues/Issue34975SecondPage.xaml.cs | Tracks created page instances via WeakReference for GC verification. |
| src/Controls/tests/TestCases.Shared.Tests/Tests/Issues/Issue34975.cs | Adds an Appium test that runs the repro flow and asserts “Test passed”. |
🤖 AI Summary
📊 Review Session —
|
| Check | Expected | Actual | Result |
|---|---|---|---|
| Tests WITHOUT fix | FAIL | PASS | ❌ |
| Tests WITH fix | PASS | PASS | ✅ |
❌ Final Verdict
VERIFICATION FAILED ❌
❌ Tests PASSED without fix (should have failed)
- The tests don't actually detect the bug
- Tests may not be testing the right behavior
Possible causes:
- Wrong fix files specified
- Tests don't actually test the fixed behavior
- The issue was already fixed in base branch
- Build caching - try clean rebuild
- Test needs different setup or conditions
Configuration
Platform: android
Test Filter: Issue34975
Base Branch: main
Merge Base: d5e39b0
Fix Files
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellPageRendererTracker.cs
Test Results Details
Test Run 1: WITHOUT Fix
Expected: Tests should FAIL (bug is present)
Actual: Tests PASSED ❌
Test Summary:
- Total:
- Passed: True
- Failed:
- Skipped:
View full test output (without fix)
Determining projects to restore...
Restored /home/vsts/work/1/s/src/Graphics/src/Graphics/Graphics.csproj (in 670 ms).
Restored /home/vsts/work/1/s/src/Essentials/src/Essentials.csproj (in 3.13 sec).
Restored /home/vsts/work/1/s/src/Controls/src/Xaml/Controls.Xaml.csproj (in 5.76 sec).
Restored /home/vsts/work/1/s/src/Core/src/Core.csproj (in 1.92 sec).
Restored /home/vsts/work/1/s/src/Core/maps/src/Maps.csproj (in 731 ms).
Restored /home/vsts/work/1/s/src/Controls/src/Core/Controls.Core.csproj (in 29 ms).
Restored /home/vsts/work/1/s/src/Controls/Maps/src/Controls.Maps.csproj (in 36 ms).
Restored /home/vsts/work/1/s/src/Controls/Foldable/src/Controls.Foldable.csproj (in 67 ms).
Restored /home/vsts/work/1/s/src/BlazorWebView/src/Maui/Microsoft.AspNetCore.Components.WebView.Maui.csproj (in 677 ms).
Restored /home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj (in 1.68 sec).
1 of 11 projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:07:30.26
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Test Run 2: WITH Fix
Expected: Tests should PASS (bug is fixed)
Actual: Tests PASSED ✅
Test Summary:
- Total:
- Passed: True
- Failed:
- Skipped:
View full test output (with fix)
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
Build FAILED.
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: Mono.AndroidTools.InstallFailedException: Unexpected install output: cmd: Failure calling service package: Broken pipe (32) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass105_0.<InstallPackage>b__0(Task`1 t) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: --- End of stack trace from previous location --- [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at AndroidDeviceExtensions.PushAndInstallPackageAsync(AndroidDevice device, PushAndInstallCommand command, CancellationToken token) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.InstallPackage(Boolean installed) [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
/home/vsts/work/1/s/.dotnet/packs/Microsoft.Android.Sdk.Linux/36.1.2/tools/Xamarin.Android.Common.Debugging.targets(333,5): error ADB0010: at Xamarin.Android.Tasks.FastDeploy.RunInstall() [/home/vsts/work/1/s/src/Controls/tests/TestCases.HostApp/Controls.TestCases.HostApp.csproj::TargetFramework=net10.0-android]
0 Warning(s)
1 Error(s)
Time Elapsed 00:11:19.13
* daemon not running; starting now at tcp:5037
* daemon started successfully
Determining projects to restore...
All projects are up-to-date for restore.
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Graphics/Debug/net10.0-android36.0/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Essentials/Debug/net10.0-android36.0/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Core/Debug/net10.0-android36.0/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Maps -> /home/vsts/work/1/s/artifacts/bin/Maps/Debug/net10.0-android36.0/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.Core/Debug/net10.0-android36.0/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.Xaml/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Xaml.dll
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Microsoft.AspNetCore.Components.WebView.Maui/Debug/net10.0-android36.0/Microsoft.AspNetCore.Components.WebView.Maui.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.Maps/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Maps.dll
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.Foldable/Debug/net10.0-android36.0/Microsoft.Maui.Controls.Foldable.dll
Controls.TestCases.HostApp -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Controls.TestCases.HostApp.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Graphics -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Graphics.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Essentials -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Essentials.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.dll
Controls.BindingSourceGen -> /home/vsts/work/1/s/artifacts/bin/Controls.BindingSourceGen/Debug/netstandard2.0/Microsoft.Maui.Controls.BindingSourceGen.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Maps.dll
Controls.Core -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Microsoft.AspNetCore.Components.WebView.Maui -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.AspNetCore.Components.WebView.Maui.dll
##vso[build.updatebuildnumber]10.0.70-ci+azdo.13910943
Controls.Foldable -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Foldable.dll
Controls.Xaml -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Xaml.dll
Controls.Maps -> /home/vsts/work/1/s/artifacts/bin/Controls.TestCases.HostApp/Debug/net10.0-android/Microsoft.Maui.Controls.Maps.dll
Build succeeded.
0 Warning(s)
0 Error(s)
Time Elapsed 00:09:07.71
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.CLOSE_SYSTEM_DIALOGS flg=0x400000 }
Broadcast completed: result=0
Logs
- Full verification log:
/home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35082/PRAgent/gate/verify-tests-fail/verification-log.txt - Test output without fix:
/home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35082/PRAgent/gate/verify-tests-fail/test-without-fix.log - Test output with fix:
/home/vsts/work/1/s/CustomAgentLogsTmp/PRState/35082/PRAgent/gate/verify-tests-fail/test-with-fix.log - UI test logs:
CustomAgentLogsTmp/UITests/
🔍 Pre-Flight — Context & Validation
Issue: #34975 - [iOS] Title view memory leak
PR: #35082 - [iOS] Fix Shell page memory leak when using TitleView with x:Name
Platforms Affected: iOS (fix), all platforms (tests run on all)
Files Changed: 1 implementation (ShellPageRendererTracker.cs), 4 test files
Key Findings
- Fix is iOS-only:
ShellPageRendererTracker.csis the iOS Shell compatibility handler - The Gate was run on Android — the fix doesn't affect Android, so the test passes on Android regardless of whether the fix is applied (explains Gate ❌ FAILED: "tests PASSED without fix" on Android)
- Test
Issue34975is taggedPlatformAffected.iOSin HostApp but the Gate ran with Android platform - The fix sets
NavigationItem.TitleView = nullbeforetvc.Disconnect()inDispose(), breaking the UIKit → NameScope → Page retain chain tvc.Disconnect()is a no-op (empty method body) — the fix is entirely in the new null assignmentTask.Delay(500)in the test creates a timing race for disposal completion
Code Review Summary
Verdict: LGTM
Confidence: medium
Errors: 0 | Warnings: 2 | Suggestions: 1
Key code review findings:
⚠️ ShellPageRendererTracker.cs:1315—tvc.Disconnect()is a no-op (empty body); comment implies it contributes to the fix but it doesn't. A future maintainer might remove theNavigationItem.TitleView = nullline thinkingDisconnect()handles cleanup.⚠️ Issue34975.cs:~41—Task.Delay(500)is fragile; if Shell disposal hasn't completed in 500ms,WaitForGCmay run too early. A deterministic trigger (e.g.,OnNavigatedFrom) would be more robust.- 💡 Test tracks
WeakReference(this)for the page but not for theTitleViewContainer— a future regression via the TitleViewContainer path could go undetected.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #35082 | Set NavigationItem.TitleView = null before tvc.Disconnect() in Dispose() |
❌ FAILED (Gate — Android platform, iOS-only fix) | ShellPageRendererTracker.cs |
Original PR |
Gate Failure Analysis
The Gate ❌ FAILED with "tests PASSED without fix" on Android. This is a test scope mismatch, not a test quality failure:
- The fix is in
ShellPageRendererTracker.cswhich is an iOS-only file (compiled only fornet*-iosandnet*-maccatalyst) - The Gate ran the test on Android where the fix file doesn't even compile
- The memory leak is iOS-specific (UIKit
NavigationItem.TitleViewstrong reference) - On Android, the GC test passes unconditionally because Android has no such leak
- The Gate would need to run on iOS to properly detect the bug
🔬 Code Review — Deep Analysis
Code Review — PR #35082
Independent Assessment
What this changes: In ShellPageRendererTracker.Dispose(bool disposing), before calling tvc.Disconnect() on the TitleViewContainer, the code now explicitly sets NavigationItem.TitleView = null first. This clears UIKit's strong native reference to the TitleViewContainer before the managed-side cleanup runs. Four test files are added: a HostApp page (Issue34975.cs), a second-page XAML pair (Issue34975SecondPage.xaml[.cs]), and an NUnit UI test.
Inferred motivation: A memory leak on iOS when navigating back from a Shell page that uses a TitleView together with x:Name on the root element. The page wasn't being GC'd after back-navigation.
Reconciliation with PR Narrative
Author claims: When Shell.TitleView and x:Name are used together on a ContentPage, UIKit's NavigationItem.TitleView retains the TitleViewContainer, which in turn holds the MAUI view tree, NameScope, and a strong reference back to the page — preventing GC. Setting NavigationItem.TitleView = null during disposal breaks the chain.
Agreement/disagreement: The root cause analysis and fix are accurate. The key observation: NavigationItem = null is set at line 1327 (outside the if (disposing) guard), but that only clears the C# reference to the navigation item. UIKit's native reference to the TitleView native object persists until it's explicitly cleared. The fix inserts that explicit clear at the right moment.
Findings
⚠️ Warning — UIContainerView.Disconnect() is a no-op; comment overstates its role
UIContainerView.Disconnect() (Shell/iOS/UIContainerView.cs) has an empty body:
internal void Disconnect()
{
}The comment on the new lines says "…so clearing this native reference is necessary to allow GC," which is accurate — but it implies tvc.Disconnect() on the following line also contributes to the fix. It doesn't. tvc.Disconnect() is a no-op and was already present before this PR. The entire fix is accomplished solely by NavigationItem.TitleView = null. A future maintainer reading the code will wonder what Disconnect() is doing for memory there, or may remove the NavigationItem.TitleView = null line thinking Disconnect() handles it. Worth updating the comment to say "this line alone is what breaks the chain; Disconnect() currently has no body."
⚠️ Warning — Task.Delay(500) in HostApp navigation handler
Issue34975.cs (HostApp), line ~41:
// A small delay lets that continuation run before we expose CheckMemoryButton.
await Task.Delay(500);Per MAUI review rules: Task.Delay in tests needs justification — "How do we know 500ms is enough?" On slow CI or a heavily loaded simulator this delay could expire before the Shell back-navigation has fully completed its disposal chain, causing GarbageCollectionHelper.WaitForGC to be invoked while the NavigationItem.TitleView = null assignment hasn't been reached yet. The WaitForGC 5-second timeout provides a safety net, but the race is real. A deterministic signal (e.g., overriding OnNavigatedFrom or hooking Disappearing on the second page to reveal the button) would be more robust than a fixed delay.
💡 Suggestion — Test only tracks the page, not the TitleViewContainer
Issue34975SecondPage.xaml.cs adds a WeakReference(this) for the page. If a future regression re-introduces the leak via the TitleViewContainer (instead of the page), the test would pass even though memory is still leaking. Tracking a WeakReference to the TitleViewContainer would make the test cover the exact UIKit object the fix operates on.
Devil's Advocate
On the Disconnect(): One could argue the code was always calling Disconnect() after clearing TitleView in UpdateTitleView(), so keeping the same call in Dispose preserves symmetry even if it's a no-op today. That's fair — the call is harmless. But it still risks misleading future readers.
On approving the fix overall: Could NavigationItem.TitleView = null during disposal cause a side effect? The only listener on TitleView changes is the UIKit layout system, which during disposal is irrelevant. UpdateTitleView() already performs this exact null assignment at line 323 for the non-null → null transition; Dispose is a subset of that path. No re-entrancy risk.
On test platform scope: The fix is iOS-only (ShellPageRendererTracker.cs is iOS-only). The test runs on all platforms. On Android/Windows there is no leak, so GarbageCollectionHelper.WaitForGC will succeed normally. This is correct behavior per MAUI test guidelines (tests should run on all platforms unless technically blocked).
Verdict: LGTM
Confidence: medium
Summary: The fix is correct, surgical, and well-motivated. Setting NavigationItem.TitleView = null before managed cleanup is exactly the right place to break the UIKit → NameScope → Page retain chain, and it mirrors the pattern already used in UpdateTitleView(). The two warnings above are comment-level and test-robustness concerns, not correctness blockers.
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #35082 | Set NavigationItem.TitleView = null before tvc.Disconnect() in Dispose() |
❌ FAILED (Gate — Android, iOS-only fix) | ShellPageRendererTracker.cs |
Original PR |
| 1 | try-fix (claude-opus-4.6) | Implement UIContainerView.Disconnect() to sever its own managed refs (remove platform subview, null _renderer/_platformView) |
✅ PASS (Android caveat*) | UIContainerView.cs |
Fixes code review concern about Disconnect() no-op |
| 2 | try-fix (claude-sonnet-4.6) | Proactive cleanup in SetDisappeared() at navigation time rather than disposal |
✅ PASS (Android caveat*) | ShellPageRendererTracker.cs |
Different timing hypothesis — earlier cleanup |
| 3 | try-fix (gpt-5.3-codex) | Clear NameScope from TitleView tree during disposal | ✅ PASS (Android caveat*) | ShellPageRendererTracker.cs |
Targets managed NameScope chain |
| 4 | try-fix (gpt-5.4) | RemoveLogicalChild for TitleView in Dispose() |
✅ PASS (Android caveat*) | ShellPageRendererTracker.cs |
Detaches from logical tree |
All Android passes are non-validating because the fix files are iOS-only (compiled only for net-ios/maccatalyst). Android has no UIKit reference chain and cannot exhibit this leak. Tests pass on Android regardless of the fix. True validation requires iOS.
Cross-Pollination
| Model | Round | New Ideas? | Details |
|---|---|---|---|
| claude-opus-4.6 | 2 | No | "NO NEW IDEAS — the five approaches cover the practical fix space for this bug" |
Exhausted: Yes
Selected Fix: PR's fix — Most surgical (single line), directly addresses UIKit strong reference, mirrors existing UpdateTitleView() pattern, no side effects, code review LGTM.
Platform Caveat Note
The Gate ❌ FAILED because it ran on Android for an iOS-only fix. The fix is in ShellPageRendererTracker.cs which only compiles for iOS/MacCatalyst. On Android, the memory leak doesn't exist, so the test passes unconditionally with or without any code changes to the iOS file. The Gate result reflects a platform scope mismatch, not a test or fix quality issue. The Gate should be re-run on iOS to properly validate the fix.
📋 Report — Final Recommendation
⚠️ Final Recommendation: REQUEST CHANGES
Phase Status
| Phase | Status | Notes |
|---|---|---|
| Pre-Flight | ✅ COMPLETE | iOS-only fix, Gate platform mismatch identified |
| Code Review | LGTM (medium) | 0 errors, 2 warnings, 1 suggestion |
| Gate | ❌ FAILED | Android platform — tests passed WITHOUT fix (iOS-only code not compiled for Android) |
| Try-Fix | ✅ COMPLETE | 4 attempts, all PASS (Android caveat — same platform mismatch as Gate) |
| Report | ✅ COMPLETE |
Code Review Impact on Try-Fix
Code review identified that tvc.Disconnect() is a no-op, which prompted Attempt 1 (claude-opus-4.6) to specifically address this by implementing UIContainerView.Disconnect() as a substantive cleanup. The code review warning about Task.Delay(500) being fragile was noted in all models' analyses but not addressed in any try-fix attempt (out of scope for try-fix). The LGTM verdict with medium confidence meant all models approached the PR's fix as correct-but-improvable, leading to exploration of alternative fix locations (timing, NameScope, logical tree).
Summary
PR #35082 fixes an iOS-only Shell page memory leak where using Shell.TitleView together with x:Name on a ContentPage prevents GC after back-navigation. The fix is a single-line addition: NavigationItem.TitleView = null before tvc.Disconnect() in ShellPageRendererTracker.Dispose(). The fix is correct, surgical, and code review returned LGTM.
However, the Gate ❌ FAILED because it was run on Android with an iOS-only fix file. ShellPageRendererTracker.cs is only compiled for iOS/MacCatalyst targets — it does not exist in the Android build. The test passed on Android without the fix because Android has no UIKit reference chain and cannot exhibit this leak. This is a platform scope mismatch in the Gate configuration, not a defect in the test or the fix.
REQUEST CHANGES is recommended due to the Gate failure (per review policy), combined with two test quality warnings from code review. These are actionable improvements the author should address before the Gate can be re-run on the correct platform.
Root Cause
UIKit's NavigationItem.TitleView holds a strong native reference to TitleViewContainer. When the page uses x:Name, MAUI's NameScope registers the page with the view tree, creating: UIKit → TitleViewContainer → MAUI view tree → NameScope → Page. When navigating back, the page is disposed but UIKit still holds the native TitleView, keeping the entire chain alive. Setting NavigationItem.TitleView = null explicitly during disposal breaks the head of this chain.
Fix Quality
The PR's fix is correct and minimal. Code review verdict: LGTM (medium confidence), 0 errors, 2 warnings:
-
tvc.Disconnect()is a no-op — The comment in the new code impliesDisconnect()contributes to the fix, but its body is empty. OnlyNavigationItem.TitleView = nullactually breaks the chain. Risk: future maintainer may remove the null assignment thinkingDisconnect()handles it. The comment should be clarified. -
Task.Delay(500)in test is fragile — If Shell's disposal chain takes longer than 500ms on a slow CI machine,WaitForGCmay be invoked beforeNavigationItem.TitleView = nullhas been called. The 5-secondWaitForGCtimeout mitigates this, but a deterministic trigger (e.g.,OnNavigatedFrom) would be more robust.
Gate re-run required on iOS to properly validate this fix. All try-fix passes were on Android, which cannot exercise iOS-only code.
🧪 UI Tests — Category Detection & Results
Build #1391786 | 🔄 inProgress | / passed (0%)
🎯 Detected categories: Shell — ran 7 of 143 matrix cells (skipped 136)
…5082) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details When Shell.TitleView and x:Name are used together on a ContentPage, the page is never garbage collected after back-navigation on iOS. This causes a memory leak that grows with every navigation round-trip. ### Root Cause x:Name on a ContentPage creates a NameScope that holds a reference back to the page, and this gets attached to the TitleView children. On back-navigation, the page is disposed but the native iOS UINavigationItem.TitleView reference was never cleared. Since iOS UIKit still holds the TitleView, the whole chain — TitleView → NameScope → Page — stays alive and the page is never collected. ### Description of Change Setting NavigationItem.TitleView = null during page disposal releases UIKit's strong native reference to the TitleViewContainer. This breaks the reference chain and allows the page to be garbage collected normally. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #34975 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/9c914487-6ce6-4fd8-b9dc-81c98f56e810" >| <video src="https://github.com/user-attachments/assets/f0266d6a-9561-4275-9015-c05d9570be78">| --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…5082) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details When Shell.TitleView and x:Name are used together on a ContentPage, the page is never garbage collected after back-navigation on iOS. This causes a memory leak that grows with every navigation round-trip. ### Root Cause x:Name on a ContentPage creates a NameScope that holds a reference back to the page, and this gets attached to the TitleView children. On back-navigation, the page is disposed but the native iOS UINavigationItem.TitleView reference was never cleared. Since iOS UIKit still holds the TitleView, the whole chain — TitleView → NameScope → Page — stays alive and the page is never collected. ### Description of Change Setting NavigationItem.TitleView = null during page disposal releases UIKit's strong native reference to the TitleViewContainer. This breaks the reference chain and allows the page to be garbage collected normally. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #34975 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/9c914487-6ce6-4fd8-b9dc-81c98f56e810" >| <video src="https://github.com/user-attachments/assets/f0266d6a-9561-4275-9015-c05d9570be78">| --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…5082) <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Details When Shell.TitleView and x:Name are used together on a ContentPage, the page is never garbage collected after back-navigation on iOS. This causes a memory leak that grows with every navigation round-trip. ### Root Cause x:Name on a ContentPage creates a NameScope that holds a reference back to the page, and this gets attached to the TitleView children. On back-navigation, the page is disposed but the native iOS UINavigationItem.TitleView reference was never cleared. Since iOS UIKit still holds the TitleView, the whole chain — TitleView → NameScope → Page — stays alive and the page is never collected. ### Description of Change Setting NavigationItem.TitleView = null during page disposal releases UIKit's strong native reference to the TitleViewContainer. This breaks the reference chain and allows the page to be garbage collected normally. Validated the behavior in the following platforms - [x] Android - [x] Windows - [x] iOS - [x] Mac ### Issues Fixed Fixes #34975 ### Output ScreenShot |Before|After| |--|--| | <video src="https://github.com/user-attachments/assets/9c914487-6ce6-4fd8-b9dc-81c98f56e810" >| <video src="https://github.com/user-attachments/assets/f0266d6a-9561-4275-9015-c05d9570be78">| --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
When Shell.TitleView and x:Name are used together on a ContentPage, the page is never garbage collected after back-navigation on iOS. This causes a memory leak that grows with every navigation round-trip.
Root Cause
x:Name on a ContentPage creates a NameScope that holds a reference back to the page, and this gets attached to the TitleView children. On back-navigation, the page is disposed but the native iOS UINavigationItem.TitleView reference was never cleared. Since iOS UIKit still holds the TitleView, the whole chain — TitleView → NameScope → Page — stays alive and the page is never collected.
Description of Change
Setting NavigationItem.TitleView = null during page disposal releases UIKit's strong native reference to the TitleViewContainer. This breaks the reference chain and allows the page to be garbage collected normally.
Validated the behavior in the following platforms
Issues Fixed
Fixes #34975
Output ScreenShot
34975-iOS-BeforeFix.mov
34975-iOS-Fix.mov