iOS开发中如何仅dismiss最顶层的viewController?
仅 dismiss 模态控制器C的解决方案
问题原因排查
首先明确系统dismissViewControllerAnimated:completion:的原生规则:默认情况下,在控制器C上调用该方法,系统会自动将 dismiss 事件转发给present出C的控制器B执行,只会移除C,不会连带B一起消失。出现两级同时dismiss的情况,通常是以下几种原因导致:
- 你实际是在B上调用了dismiss方法,而非C
- 控制器层级存在自定义转场、导航控制器嵌套等特殊场景,presenting 链路出现混乱
- 存在手势、通知、代理回调的额外触发,在C被dismiss的同时额外触发了B的dismiss逻辑
正确实现代码
方案1:规范调用方式(优先推荐)
不要在C自身调用dismiss,主动指定由present出C的B执行操作,在C的内部实现代码如下:
// ControllerC 内部执行 dismiss 逻辑 [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
如果存在导航控制器嵌套,C的presentingViewController是导航控制器,可修改为:
// 适配导航容器的场景 if (self.presentingViewController.navigationController) { [self.presentingViewController.navigationController dismissViewControllerAnimated:YES completion:nil]; } else { [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }
方案2:弱引用持有B实例调用
如果层级结构特别复杂,可在C中声明一个weak属性持有B的实例,直接让B执行dismiss:
// ControllerC.h 中声明属性 @property (nonatomic, weak) UIViewController *presentFromViewController; // present 出 C 的时候赋值 ControllerC *c = [[ControllerC alloc] init]; c.presentFromViewController = self; // 此处self是ControllerB [self presentViewController:c animated:YES completion:nil]; // C 内部执行 dismiss [self.presentFromViewController dismissViewControllerAnimated:YES completion:nil];
异常排查
如果修改调用逻辑后仍然出现两级同时消失的问题,可添加断点检查dismissViewControllerAnimated的调用栈,排查是否有其他代码同时触发了B的dismiss逻辑。
内容的提问来源于stack exchange,提问作者ximmyxiao
相关产品推荐
相关产品推荐

