You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.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;
    }

    // 检查栈顶是否为
相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:15:07