连续点击按钮触发转场动画时App崩溃,报错子控制器需同属父控制器
问题分析与解决方案
崩溃原因
连续点击按钮时,前一次转场动画的completion回调尚未执行,视图控制器的父子关系处于未完全更新的中间状态。此时再次调用transition(from:to:...)方法,会导致参与转场的两个视图控制器不满足"拥有共同父视图控制器"的要求,从而触发NSInvalidArgumentException异常。缩短动画时长时,completion回调会更快执行,父子关系及时更新,因此不会崩溃,但动画体验变差。
修复方案
核心思路是禁止在转场动画进行中触发新的转场,通过添加状态锁避免并发执行转场逻辑,同时修正视图控制器父子关系的处理流程:
- 添加转场状态标记
在当前控制器中增加私有属性,标记是否正在执行转场:
private var isPerformingTransition = false
- 修改转场方法逻辑
更新transitionBetweenViews方法,加入状态判断,并规范视图控制器的父子关系处理:
func transitionBetweenViews() { // 防止连续触发转场动画 guard !isPerformingTransition else { return } isPerformingTransition = true let fromViewController = aController let toViewController = bController let options: UIView.AnimationOptions = self.viewModel.State == .something ? .transitionFlipFromRight : .transitionFlipFromLeft // 处理目标视图控制器的添加逻辑:若尚未成为子VC则完成添加流程 if !self.children.contains(toViewController) { addChild(toViewController) containerView.fillWithView(toViewController.view) toViewController.didMove(toParent: self) } // 标记源视图控制器即将被移除 fromViewController.willMove(toParent: nil) self.transition(from: fromViewController, to: toViewController, duration: 0.5, options: options, animations: nil, completion: { [weak self] _ in guard let self = self else { return } // 完成源视图控制器的移除 fromViewController.removeFromParent() // 重置转场标记,允许下次触发 self.isPerformingTransition = false }) }
额外注意事项
- 确保
aController和bController的引用始终指向正确的视图控制器实例,避免出现引用失效或错误的情况。 - 转场过程中涉及的视图容器
containerView需保证布局正确,避免视图层级混乱。
内容的提问来源于stack exchange,提问作者Sudha Tiwari
相关产品推荐
相关产品推荐

