iOS 12系统下self.dismiss方法失效高版本运行正常的原因及修复方案
问题原因
- 首先是代码中动画块的写法存在错误:
UIView.animate的animations闭包本身默认在主队列执行,你额外套了一层DispatchQueue.main.async,会导致stackView的frame修改没有被当前动画块捕获,动画块因为没有可执行的属性动画,在iOS 12下会立刻触发completion回调,此时你异步派发的frame修改才刚要执行,视图上存在未完成的动画。 - iOS 12的UIKit存在已知行为:当视图控制器的视图上有正在进行的未完成动画时,调用
dismiss(animated: true)会被系统静默忽略,不会执行dismiss逻辑也不会触发completion回调。而iOS 13及以上版本对该场景做了兼容优化,会自动处理未完成动画后执行dismiss,所以你的代码在高版本系统可以正常运行。 - 附加问题:你在动画completion闭包中直接强引用self调用dismiss,虽然不是本次问题的直接诱因,但存在循环引用风险。
修复方案
- 移除animations闭包里冗余的
DispatchQueue.main.async包裹,确保frame修改被动画块正常捕获,动画执行时序正常:
UIView.animate(withDuration: 0.3, animations: { [weak self] in guard let self = self else { return } // 移除多余的主队列异步派发,直接修改frame self.stackViewMain.frame = CGRect(origin: CGPoint(x: self.stackViewMain.frame.origin.x, y: self.view.bounds.height), size: self.stackViewMain.bounds.size) }) { [weak self] _ in guard let self = self else { return } self.dismiss(animated: true) { self.viewModel.animationdDidFinishControllerWillDismiss() } }
- 如果经过上述修改后iOS 12仍偶现不执行dismiss的情况,可以强制在dismiss前停止所有未完成的视图动画:
// 在dismiss前先停止所有未完成的视图动画 self.view.layer.removeAllAnimations() self.dismiss(animated: true) { self.viewModel.animationdDidFinishControllerWillDismiss() }
- 如果上述方案都不生效,也可以替换为调用presentingViewController的dismiss方法,兼容性更好:
self.presentingViewController?.dismiss(animated: true) { self.viewModel.animationdDidFinishControllerWillDismiss() }
内容的提问来源于stack exchange,提问作者Apple John
相关产品推荐
相关产品推荐

