.NET MAUI iOS重复推送同视图控制器抛ObjCRuntime.ObjCException求助
.NET MAUI表单iOS重复推送视图控制器异常的跨平台修复方案
我开发了一个.NET MAUI表单应用,每个视图对应一个问题,切换至下一个问题时类型可能相同或不同。当问题类型相同时复用同一视图,该逻辑在Android上正常,但iOS抛出ObjCRuntime.ObjCException,提示不允许重复推送同一视图控制器实例。
报错信息
ObjCRuntime.ObjCException Message = Objective-C exception thrown. Name: NSInvalidArgumentException Reason: <Microsoft_Maui_Controls_Platform_Compatibility_ShellSectionRenderer: 0x116f56800> is pushing the same view controller instance (<Microsoft_Maui_Platform_PageViewController: 0x117869db0>) more than once which is not supported and is most likely an error in the application : com.geicam.asociados Native stack trace: 0 CoreFoundation 0x00000001804ae0f8 __exceptionPreprocess + 172 1 libobjc.A.dylib 0x0000000180087db4 objc_exception_throw + 56 2 UIKitCore 0x0000000184bf9334 -[UINavigationController pushViewController:transition:forceImmediate:] + 3736 3 UIKitCore 0x0000000184bf832c -[UINavigationController pushViewController:animated:] + 756 4 libxamarin-dotnet-debug.dylib 0x0000000107f94bd4 xamarin_dyn_objc_msgSendSuper + 164 5 geicam.asociados 0x000000010589d95c interp_to_native_trampoline + 156 6 libmonosgen-2.0.dylib 0x00000001086ff6f8 ves_pinvoke_method + 584 7 libmonosgen-2.0.dylib 0x00000001086f3e84 mono_interp_exec_method + 3052 8 libmonosgen-2.0.dylib 0x00000001086f194c interp_runtime_invoke + 244 9 libmonosgen-2.0.dylib 0x000000010860abf0 mono_jit_runtime_invoke + 1116 10 libmonosgen-2.0.dylib 0x00000001087c6cb0 mono_runtime_try_invoke + 156 11 libmonosgen-2.0.dylib 0x00000001087c9d28 mono_runtime_invoke + 488 12 geicam.asociados 0x00000001058bf400 _ZL30native_to_managed_trampoline_9P11objc_objectP13objc_selectorPP11_MonoMethodj + 316 13 geicam.asociados 0x00000001059103bc -[UIKit_UIControlEventProxy BridgeSelector] + 44 14 UIKitCore 0x00000001853d58ec -[UIApplication sendAction:to:from:forEvent:] + 96 15 UIKitCore 0x0000000184ce23d0 -[UIControl sendAction:to:forEvent:] + 108 16 UIKitCore 0x0000000184ce2714 -[UIControl _sendActionsForEvents:withEvent:] + 268 17 UIKitCore 0x0000000184cdf188 -[UIButton _sendActionsForEvents:withEvent:] + 120 18 UIKitCore 0x0000000184ce13ac -[UIControl touchesEnded:withEvent:] + 392 19 UIKitCore 0x0000000185409354 -[UIWindow _sendTouchesForEvent:] + 900 20 UIKitCore 0x000000018540a878 -[UIWindow sendEvent:] + 3104 21 UIKitCore 0x00000001853ea238 -[UIApplication sendEvent:] + 580 22 UIKitCore 0x000000018546dff4 __dispatchPreprocessedEventFromEventQueue + 1684 23 UIKitCore 0x0000000185470e90 __processEventQueue + 5604 24 UIKitCore 0x00000001854697f0 __eventFetcherSourceCallback + 160 25 CoreFoundation 0x000000018040ee48 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24 26 CoreFoundation 0x000000018040ed90 __CFRunLoopDoSource0 + 172 27 CoreFoundation 0x000000018040e500 __CFRunLoopDoSources0 + 232 28 CoreFoundation 0x0000000180408be8 __CFRunLoopRun + 768 29 CoreFoundation 0x00000001804084d4 CFRunLoopRunSpecific + 572 30 GraphicsServices 0x000000018ef2aae4 GSEventRunModal + 160 31 UIKitCore 0x00000001853d0a28 -[UIApplication _run] + 868 32 UIKitCore 0x00000001853d46b0 UIApplicationMain + 124 33 libxamarin-dotnet-debug.dylib 0x0000000107f4fa84 xamarin_UIApplicationMain + 60 34 libmonosgen-2.0.dylib 0x0000000108700abc do_icall + 316 35 libmonosgen-2.0.dylib 0x00000001086ff35c do_icall_wrapper + 356 36 libmonosgen-2.0.dylib 0x00000001086f3dac mono_interp_exec_method + 2836 37 libmonosgen-2.0.dylib 0x00000001086f194c interp_runtime_invoke + 244 38 libmonosgen-2.0.dylib 0x000000010860abf0 mono_jit_runtime_invoke + 1116 39 libmonosgen-2.0.dylib 0x00000001087c5c9c mono_runtime_invoke_checked + 148 40 libmonosgen-2.0.dylib 0x00000001087cd27c mono_runtime_exec_main_checked + 116 41 libmonosgen-2.0.dylib 0x000000010865ee78 mono_jit_exec + 364 42 libxamarin-dotnet-debug.dylib 0x0000000107f93a38 xamarin_main + 2320 43 geicam.asociados 0x0000000105981560 main + 72 44 dyld 0x000000010654d544 start_sim + 20 45 ??? 0x0000000106652154 0x0 + 4402258260 46 ??? 0xb162800000000000 0x0 + 12781919429919244288 Origin = Microsoft.iOS
当前跳转逻辑代码
public async void CargarView(int id) { switch ((enumFormTipoPregunta)id) { case enumFormTipoPregunta.TextoCorto: var navigationTextoCorto = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaTCortoView)}", navigationTextoCorto); break; case enumFormTipoPregunta.Parrafo: var navigationParrafo = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaTLargoView)}", navigationParrafo); break; case enumFormTipoPregunta.Opcion: var navigationParameter = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaOpcionView)}", navigationParameter); break; case enumFormTipoPregunta.Multiple: var navigationFormulario = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaMultipleView)}", navigationFormulario); break; case enumFormTipoPregunta.Desplegable: var navigationDesplegable = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaOpcionView)}", navigationDesplegable); break; case enumFormTipoPregunta.Multiple2Col: var navigationMultiple2Col = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaMultipleView)}", navigationMultiple2Col); break; case enumFormTipoPregunta.Numerico: var navigationNumerico = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaNumericaView)}", navigationNumerico); break; case enumFormTipoPregunta.Valoracion: var navigationValoracion = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaValoracionView)}", navigationValoracion); break; case enumFormTipoPregunta.Fecha: var navigationFecha = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; await Shell.Current.GoToAsync($"{nameof(PreguntaFechaView)}", navigationFecha); break; default: break; } }
跨平台兼容修改方案
方案1:创建新视图实例推送(直接兼容)
放弃Shell的视图复用机制,每次跳转时手动创建对应视图的新实例,通过导航推送:
public async void CargarView(int id) { Page targetPage = null; var navigationParams = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; switch ((enumFormTipoPregunta)id) { case enumFormTipoPregunta.TextoCorto: targetPage = new PreguntaTCortoView(); break; case enumFormTipoPregunta.Parrafo: targetPage = new PreguntaTLargoView(); break; case enumFormTipoPregunta.Opcion: case enumFormTipoPregunta.Desplegable: targetPage = new PreguntaOpcionView(); break; case enumFormTipoPregunta.Multiple: case enumFormTipoPregunta.Multiple2Col: targetPage = new PreguntaMultipleView(); break; case enumFormTipoPregunta.Numerico: targetPage = new PreguntaNumericaView(); break; case enumFormTipoPregunta.Valoracion: targetPage = new PreguntaValoracionView(); break; case enumFormTipoPregunta.Fecha: targetPage = new PreguntaFechaView(); break; default: return; } // 传递参数到视图(可根据视图实际情况选择构造函数或属性赋值) if (targetPage is IQuestionView questionView) { questionView.SetData(formul, cfo, gRespu); } await Shell.Current.Navigation.PushAsync(targetPage); } // 定义统一接口规范视图参数设置 public interface IQuestionView { void SetData(object formulario, object contador, object respuesta); }
每个问题视图实现IQuestionView接口,在SetData方法中更新控件或绑定数据。此方法简单直接,兼容所有平台,仅增加少量内存开销,适合表单场景。
方案2:复用视图+数据刷新(最优兼容)
保留Shell导航,跳转前检查栈顶视图类型,若与目标类型一致则直接刷新数据,不执行跳转:
public async void CargarView(int id) { Type targetType = null; var navigationParams = new Dictionary<string, object> { { "Formulario", formul }, { "Contador", cfo }, { "Respuesta", gRespu } }; switch ((enumFormTipoPregunta)id) { case enumFormTipoPregunta.TextoCorto: targetType = typeof(PreguntaTCortoView); break; case enumFormTipoPregunta.Parrafo: targetType = typeof(PreguntaTLargoView); break; case enumFormTipoPregunta.Opcion: case enumFormTipoPregunta.Desplegable: targetType = typeof(PreguntaOpcionView); break; case enumFormTipoPregunta.Multiple: case enumFormTipoPregunta.Multiple2Col: targetType = typeof(PreguntaMultipleView); break; case enumFormTipoPregunta.Numerico: targetType = typeof(PreguntaNumericaView); break; case enumFormTipoPregunta.Valoracion: targetType = typeof(PreguntaValoracionView); break; case enumFormTipoPregunta.Fecha: targetType = typeof(PreguntaFechaView); break; default: return; } // 检查栈顶是否为
相关产品推荐
相关产品推荐

