iPad端UIKit崩溃:UISplitViewController层级不一致问题求助
iPad端UIKit崩溃:UIViewControllerHierarchyInconsistency
我的App在iPad运行时触发UIKit崩溃,崩溃类型为UIViewControllerHierarchyInconsistency,具体错误是将同一UISplitViewController实例<UISplitViewController: 0x10b527030>作为自身的子视图控制器添加,目前无法稳定复现该问题。
完整崩溃报告如下:
Thread 0 Crashed: 0 CoreFoundation 0x32dd56684 __exceptionPreprocess 1 libobjc.A.dylib 0x31e1f2190 objc_exception_throw 2 CoreFoundation 0x32de4a6a8 +[NSException raise:format:] 3 UIKitCore 0x3321e3cf8 -[UIViewController _addChildViewController:] 4 UIKitCore 0x3321e36fc -[UIViewController _addChildViewController:performHierarchyCheck:notifyWillMove:] 5 UIKitCore 0x3323a2e40 -[UISplitViewController addChildViewController:] 6 UIKitCore 0x3323a2a5c -[UIPanelController _addIdentifiedChildViewController:] 7 UIKitCore 0x332488c7c __56-[UIPanelController _collapseWithTransitionCoordinator:]_block_invoke_4 8 UIKitCore 0x332488a84 +[UIPanelController _withDisabledAppearanceTransitions:forVisibleDescendantsOf:perform:] 9 UIKitCore 0x332488750 -[UIPanelController _withDisabledAppearanceTransitionsPerform:] 10 UIKitCore 0x3324886b0 __56-[UIPanelController _collapseWithTransitionCoordinator:]_block_invoke_3 11 UIKitCore 0x332357dcc +[UIViewController _performWithoutDeferringTransitionsAllowingAnimation:actions:] 12 UIKitCore 0x33205a104 __56-[UIPanelController _collapseWithTransitionCoordinator:]_block_invoke_2 13 UIKitCore 0x332057810 +[UIView(Animation) performWithoutAnimation:] 14 UIKitCore 0x3323c0714 __56-[UIPanelController _collapseWithTransitionCoordinator:]_block_invoke 15 UIKitCore 0x3322b18bc -[_UIViewControllerTransitionCoordinator _applyBlocks:releaseBlocks:] 16 UIKitCore 0x3322b17b4 -[_UIViewControllerTransitionContext __runAlongsideAnimations] 17 UIKitCore 0x332840498 -[_UIWindowAnimationController animateTransition:] 18 UIKitCore 0x3324dd8ac -[UIWindow _adjustSizeClassesAndResizeWindowToFrame:] 19 UIKitCore 0x3321465a4 -[UIWindow _resizeWindowFrameToSceneBoundsIfNecessary] 20 UIKitCore 0x332145aa4 -[UIWindow _sceneBoundsDidChange] 21 UIKitCore 0x33232b470 -[_UIScenefbsSceneBasedMetricsCalculator _updateMetricsOnWindows:animated:] 22 UIKitCore 0x33232b0b0 -[UIWindowScene _computeMetricsForWindows:animated:] 23 UIKitCore 0x3321a5d7c __55-[UIWindowScene _computeMetrics:withTransitionContext:]_block_invoke 24 UIKitCore 0x3323d3b84 -[UIWindowScene _computeTraitCollectionAndCoordinateSpaceForcingDelegateCallback:withAction:] 25 UIKitCore 0x3323d448c -[UIWindowScene _computeMetrics:withTransitionContext:] 26 UIKitCore 0x3325f2d70 ___UIWindowHostingScenePerformUpdateWithEffectiveSettings_block_invoke_2 27 UIKitCore 0x332357dcc +[UIViewController _performWithoutDeferringTransitionsAllowingAnimation:actions:] 28 UIKitCore 0x3325f2cf8 ___UIWindowHostingScenePerformUpdateWithEffectiveSettings_block_invoke 29 UIKitCore 0x332057810 +[UIView(Animation) performWithoutAnimation:] 30 UIKitCore 0x3325f1df4 _UIWindowHostingScenePerformUpdateWithEffectiveSettings 31 UIKitCore 0x3325f1d10 -[UIScene _guardedSetOverrideSettings:] 32 UIKitCore 0x3325f1f0c -[UIScene _applyOverrideSettings:forActions:] 33 UIKitCore 0x332f64e98 -[UIWindowScene _applySnapshotSettings:forActions:] 34 UIKitCore 0x332d9c8e8 -[UIApplication _createSnapshotContextForScene:withName:performLayoutWithSettings:] 35 UIKitCore 0x332d9d93c __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_3 36 FrontBoardServices 0x35c734500 -[FBSSceneSnapshotAction _executeNextRequest] 37 FrontBoardServices 0x35c73451c [inlined] -[FBSSceneSnapshotAction _executeNextRequest] 38 FrontBoardServices 0x35c73451c -[FBSSceneSnapshotAction _executeNextRequest] 39 FrontBoardServices 0x35c733ff0 -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:] 40 UIKitCore 0x332d9d88c __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke_2 41 UIKitCore 0x332d9d1d0 -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:] 42 UIKitCore 0x332d9d778 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke 43 UIKitCore 0x3325f1e58 -[UIScene _enableOverrideSettingsForActions:] 44 UIKitCore 0x3325f2078 -[UIScene _performSystemSnapshotWithActions:] 45 UIKitCore 0x332d9d610 -[UIApplication _performSnapshotsWithAction:forScene:completion:] 46 UIKitCore 0x3331a518c __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionContext:]_block_invoke_3 47 UIKitCore 0x3331a5028 __98-[_UISceneSnapshotBSActionsHandler _respondToActions:forFBSScene:inUIScene:fromTransitionContext:]_block_invoke_2 48 UIKitCore 0x3321e41a8 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] 49 UIKitCore 0x3322a34b8 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] 50 UIKitCore 0x3322a30d0 -[UIApplicationSceneClientAgent scene:handleEvent:withCompletion:] 51 FrontBoardServices 0x35c6d814c -[FBSScene updater:didUpdateSettings:withDiff:transitionContext:completion:] 52 FrontBoardServices 0x35c6e72dc __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke_2 53 FrontBoardServices 0x35c6e7194 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] 54 FrontBoardServices 0x35c6eb528 __94-[FBSWorkspaceScenesClient _queue_updateScene:withSettings:diff:transitionContext:completion:]_block_invoke 55 libdispatch.dylib 0x33cb02cbc _dispatch_client_callout 56 libdispatch.dylib 0x33caa6ea8 _dispatch_block_invoke_direct$VARIANT$mp 57 FrontBoardServices 0x35c6e86b0 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ 58 FrontBoardServices 0x35c6e8638 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] 59 FrontBoardServices 0x35c6e854c -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] 60 CoreFoundation 0x32dd2b120 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 61 CoreFoundation 0x32dd2b0b8 __CFRunLoopDoSource0 62 CoreFoundation 0x32dd28d9c __CFRunLoopDoSources0 63 CoreFoundation 0x32dd27f38 __CFRunLoopRun 64 CoreFoundation 0x32dd277d4 CFRunLoopRunSpecific 65 GraphicsServices 0x3ad1d5810 GSEventRunModal 66 UIKitCore 0x33239d264 -[UIApplication _run] 67 UIKitCore 0x332447908 UIApplicationMain 68 SampleApp 0x202627540 main (main.m:21) 69 <unknown> 0x1c740b228 <redacted>
问题分析
从崩溃调用栈能看出,崩溃发生在UIPanelController的折叠流程中,系统内部尝试将UISplitViewController实例作为自身的子控制器添加,触发了UIKit的层级一致性校验失败。整个流程和窗口尺寸变更、系统快照操作相关(栈中包含_resizeWindowFrameToSceneBoundsIfNecessary、_performSnapshotsWithAction等方法),大概率是界面状态切换时的竞态条件导致的偶发问题。
排查与修复建议
- 检查自定义的
UISplitViewController子类或相关容器控制器代码,确保没有手动调用addChildViewController:时传入自身实例的逻辑 - 若实现了自定义分栏控制器的状态切换逻辑,需确保在切换前正确处理子控制器的层级关系,避免在动画或过渡过程中重复添加控制器
- 针对iPad的多窗口、尺寸类变更场景,添加防御性校验:在添加子控制器前,判断目标控制器是否为当前控制器或已存在于层级结构中
- 使用Xcode的
UIViewController Hierarchy Debugging工具,在接近崩溃的场景下实时检查控制器层级,定位异常来源
内容的提问来源于stack exchange,提问作者Sourabh
相关产品推荐
相关产品推荐

