使用modalPresentationStyle = .overCurrentContext后屏幕冻结问题求助
问题排查与解决方案
核心原因
- 重复执行dismiss操作:你同时调用了
self.controller?.dismiss(animated: true)和self.nvc?.dismiss(animated: true),但实际上只需要dismiss被present出来的根控制器(也就是nvc)即可,重复dismiss会导致UI线程的动画队列混乱,引发冻结。 - viewDidLoad中立即push的时序问题:在
FirstViewController的viewDidLoad里直接push到SecondViewController,此时导航控制器的present动画还未完成,连续的导航栈动画+present动画会导致UIKit的动画系统冲突,埋下冻结隐患。
修复步骤
1. 移除重复的dismiss调用
只需要保留对目标控制器的单次dismiss操作,修改第4步的代码:
// 直接调用当前控制器的dismiss即可,无需同时调用两个 self.dismiss(animated: true, completion: nil) // 或者持有nvc引用时,也可以用: // self.nvc?.dismiss(animated: true, completion: nil)
2. 调整push的执行时机
把FirstViewController中push到SecondViewController的操作从viewDidLoad移到viewDidAppear中,确保present动画完成后再执行push,同时避免重复触发:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) guard let nav = navigationController else { return } if nav.topViewController is FirstViewController { showSecondViewController(parentController: nav) } }
3. 优化pop与dismiss的时序
在SecondViewController的pop操作中,添加completion回调,确认pop完成后再触发dismiss,避免动画叠加冲突:
// 修改pop操作,增加完成回调 navigationController?.popViewController(animated: animated) { [weak self] in self?.dismissModal() } // 单独封装dismiss逻辑 private func dismissModal() { self.dismiss(animated: true, completion: nil) }
验证要点
- 确保整个流程中只有一次dismiss操作,针对被present的根导航控制器
- 所有导航栈操作(push/pop)都在present动画完成后执行,避免动画冲突
- 使用
weak self避免循环引用,防止内存泄漏间接导致的UI冻结
内容的提问来源于stack exchange,提问作者Asif Raza
相关产品推荐
相关产品推荐

