iOS端MAUI应用操作导航栈后页面加载崩溃(空引用异常)求助
iOS端加载新页面时操作导航栈导致NullReferenceException崩溃
问题场景
导航栈初始包含Page1、Page2,从Page2跳转至Page3时,在Page3初始化阶段移除导航栈中的Page2,待Page3加载完成后应用崩溃,仅iOS端出现该问题。
代码实现
MainThread.InvokeOnMainThreadAsync(() => { while (pageElementType != endPageType) { if (pageElementType == startPageType) { removePageIndex = index + 1; } else if (removePageIndex > 0) { try { // 注释掉该行后,跳转至下一页后应用不会崩溃 navService.RemovePage(navService.NavigationStack[removePageIndex]); index--; } catch (Exception ex) { // 记录异常 Common.Log.Error($"{nameof(ManipulateNavStack)}", ex); } } index++; if (index < navService.NavigationStack.Count) { pageElementType = ((BaseViewModel)navService.NavigationStack[index].BindingContext).PageType; } else { break; } } });
异常信息
Object reference not set to an instance of an object at Microsoft.Maui.Controls.Handlers.Compatibility.NavigationRenderer.ParentingViewController.WillMoveToParentViewController.Full Path: System.NullReferenceException: Object reference not set to an instance of an object at Microsoft.Maui.Controls.Handlers.Compatibility.NavigationRenderer.ParentingViewController.WillMoveToParentViewController(UIViewController parent) at UIKit.UIApplication.UIApplicationMain(Int32 argc, String[] argv, IntPtr principalClassName, IntPtr delegateClassName) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 61 at UIKit.UIApplication.Main(String[] args, Type principalClass, Type delegateClass) in /Users/builder/azdo/_work/1/s/xamarin-macios/src/UIKit/UIApplication.cs:line 96 at xxxxx.Mobile.Program.Main(String[] args
已尝试在主线程执行移除操作,但问题依旧。
问题分析
该崩溃源于iOS导航控制器生命周期与MAUI导航栈操作不同步:Page3尚未完成入栈渲染时,就修改导航栈移除Page2,导致MAUI兼容性渲染器NavigationRenderer内部的ParentingViewController处理生命周期事件时,引用的页面已失效,触发空引用异常。同时原代码在遍历导航栈的同时修改栈结构,容易导致索引混乱,加剧引用失效问题。
解决方案
方案1:延迟操作至Page3完全加载后
不在Page3初始化阶段修改导航栈,而是在OnAppearing事件触发后执行移除逻辑,此时页面已完成入栈与渲染,生命周期状态稳定:
// 在Page3的代码中 protected override void OnAppearing() { base.OnAppearing(); MainThread.BeginInvokeOnMainThread(() => { // 执行移除Page2的逻辑 ManipulateNavStack(); }); }
方案2:调整导航栈操作时机
先完成Page3的跳转,再执行移除操作,避免跳转过程中修改栈结构:
// 替代原有跳转+移除逻辑 await navService.PushAsync(page3); // 跳转完成后移除Page2 MainThread.BeginInvokeOnMainThread(() => { var page2 = navService.NavigationStack.FirstOrDefault(p => p.GetType() == typeof(Page2)); if (page2 != null) { navService.RemovePage(page2); } });
方案3:批量移除避免遍历修改冲突
先收集所有需要移除的页面,再批量执行移除操作,避免遍历栈时修改栈结构导致的索引混乱:
MainThread.InvokeOnMainThreadAsync(() => { var pagesToRemove = new List<Page>(); foreach (var page in navService.NavigationStack) { var vm = page.BindingContext as BaseViewModel; if (vm != null && vm.PageType == 目标移除页面类型) { pagesToRemove.Add(page); } } // 批量移除页面 foreach (var page in pagesToRemove) { navService.RemovePage(page); } });
内容的提问来源于stack exchange,提问作者Pramod Patil
相关产品推荐
相关产品推荐

