Repository: dotnet/maui
File: src/Controls/src/Core/Compatibility/Handlers/NavigationPage/iOS/NavigationRenderer.cs (C#)

Code before:
			ElementChanged?.Invoke(this, e);
		}

		protected virtual async Task<bool> OnPopToRoot(Page page, bool animated)
		{
			_ignorePopCall = true;
			_ = page.ToPlatform(MauiContext);
			var renderer = (IPlatformViewHandler)page.Handler;
			if (renderer == null || renderer.ViewController == null)
				return false;

			var task = GetAppearedOrDisappearedTask(page);

			var poppedControllers = PopToRootViewController(animated);

			_ignorePopCall = false;
			var success = !await task;

			if (poppedControllers is not null)
			{
				foreach (var poppedController in poppedControllers)
				{
					if (poppedController is ParentingViewController parentingViewController)
					{
						parentingViewController.Disconnect(false);
					}
					else
					{
						poppedController?.Dispose();
					}
				}
			}

			UpdateToolBarVisible();
			return success;
		}

		protected virtual async Task<bool> OnPopViewAsync(Page page, bool animated)
		{
			if (_ignorePopCall)
				return true;

			_ = page.ToPlatform(MauiContext);
			var renderer = (IPlatformViewHandler)page.Handler;
			if (renderer == null || renderer.ViewController == null)
				return false;

			if (page != ((ParentingViewController)TopViewController).Child)
				throw new NotSupportedException("Popped page does not appear on top of current navigation stack, please file a bug.");

			var task = GetAppearedOrDisappearedTask(page);

Review comment (performance):
I looked into this a bit. The changes here are aiming to explicitly clean up for pages popped via `PopToRootAsync`, similar to what’s already done in `PopAsync`.

However, I’m not sure if that’s the right approach in the first place. Once a page is removed from the navigation stack, it should be eligible for GC naturally unless something is strongly holding on to it. Forcing early cleanup might introduce side effects.

I also wrote a device test using `TitleView` and `PopToRootAsync`, and all objects were collected as expected. 

The destructor not being called immediately is expected and doesn’t necessarily indicate a memory leak.

```csharp
[Fact(DisplayName = "PopToRoot Does Not Leak")]
public async Task PopToRootDoesNotLeak()
{
    SetupBuilder();

    var references = new List<WeakReference>();
    var launcherPage = new NavigationPage(new ContentPage());
    var window = new Window(launcherPage);

    await CreateHandlerAndAddToWindow<WindowHandlerStub>(window, async handler =>
    {
        var label = new Label() { Text = "Page Title" };
        var page = new ContentPage
        {
            Content = new Label() { Text = "Hello !" }
        };
        NavigationPage.SetTitleView(page, label);

        await launcherPage.Navigation.PushAsync(page);

        references.Add(new(label));
        references.Add(new(page));
        references.Add(new(page.Handler));
        references.Add(new(page.Handler.PlatformView));

        await launcherPage.Navigation.PopToRootAsync();
    });

    await AssertionExtensions.WaitForGC(references.ToArray());
}
```
@mattleibow your thoughts?

Code after:
		{
			ElementChanged?.Invoke(this, e);
		}

		protected virtual async Task<bool> OnPopToRoot(Page page, bool animated)
		{
			_ignorePopCall = true;
			_ = page.ToPlatform(MauiContext);
			var renderer = (IPlatformViewHandler)page.Handler;
			if (renderer == null || renderer.ViewController == null)
				return false;

			var task = GetAppearedOrDisappearedTask(page);

			var poppedControllers = PopToRootViewController(animated);

			_ignorePopCall = false;
			var success = !await task;

			if (poppedControllers is not null)
			{
				foreach (var poppedController in poppedControllers)
				{
					if (poppedController is ParentingViewController parentingViewController)
					{
						parentingViewController.Disconnect(false);
					}
					else
					{
						poppedController?.Dispose();
					}
				}
			}

			UpdateToolBarVisible();
			return success;
		}

		protected virtual async Task<bool> OnPopViewAsync(Page page, bool animated)
		{
			if (_ignorePopCall)
				return true;

			_ = page.ToPlatform(MauiContext);
			var renderer = (IPlatformViewHandler)page.Handler;
			if (renderer == null || renderer.ViewController == null)
				return false;

			if (page != ((ParentingViewController)TopViewController).Child)
				throw new NotSupportedException("Popped page does not appear on top of current navigation stack, please file a bug.");