You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS侧滑pop当前viewController时添加确认提示的异常问题求解

问题根因

你当前仅重写了popViewController(animated:)方法,未适配系统自带的侧滑返回手势interactivePopGestureRecognizer的拦截逻辑。侧滑手势触发时,系统已经启动了pop交互流程,此时你返回nil中断pop操作会导致手势状态无法正常重置,导航栈与界面渲染状态不一致,最终出现生命周期方法调用异常、界面冻结的问题。

修复方案

1. 自定义导航控制器适配侧滑手势

让自定义导航控制器遵守UIGestureRecognizerDelegate协议,同步处理手势触发的拦截逻辑,修改后代码如下:

class MyCustomNavController: UINavigationController {
    var popHandler: (() -> Bool)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        interactivePopGestureRecognizer?.delegate = self
    }

    override func popViewController(animated: Bool) -> UIViewController? {
        guard popHandler?() != false else {
            return nil
        }
        popHandler = nil
        return super.popViewController(animated: animated)
    }
    
    // 每次push新控制器时重置旧的popHandler,避免不同页面逻辑互相干扰
    override func pushViewController(_ viewController: UIViewController, animated: Bool) {
        popHandler = nil
        super.pushViewController(viewController, animated: animated)
    }
}

extension MyCustomNavController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        // 仅处理侧滑返回手势
        guard gestureRecognizer == interactivePopGestureRecognizer else {
            return true
        }
        // 导航栈内只有一个控制器时不允许侧滑返回
        guard viewControllers.count > 1 else {
            return false
        }
        // 同步使用popHandler的逻辑判断是否允许手势触发
        return popHandler?() ?? true
    }
}

2. 修正编辑页面的popHandler逻辑

手动触发pop前先清空popHandler,避免重复触发拦截逻辑,修改后代码如下:

func setupPopHandler() {
    guard let navigationController = self.navigationController as? MyCustomNavController else {
        return
    }
       
    navigationController.popHandler = { [weak self] in
        guard let self = self else { return true }
        
        if self.hasChangedFields(), self.hasUnsavedWork == true {
            let alert = UIAlertController(title: "提示", message: "你有未保存的修改", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "保存", style: .default, handler: { [weak self] action in
                guard let self = self else { return }
                // 此处执行你的保存逻辑,保存完成后手动pop
                self.navigationController?.popHandler = nil
                self.navigationController?.popViewController(animated: true)
            }))
            alert.addAction(UIAlertAction(title: "放弃修改", style: .destructive, handler: { [weak self] action in
                guard let self = self else { return }
                self.hasUnsavedWork = false
                // 手动pop前清空popHandler避免重复拦截
                self.navigationController?.popHandler = nil
                self.navigationController?.popViewController(animated: true)
            }))
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            self.present(alert, animated: true)
            
            return false
        } else {
            return true
        }
    }
}

优化建议

  • 如果存在多个需要拦截pop的页面,建议将popHandler作为UIViewController的扩展属性,导航控制器触发拦截时读取当前topViewController的对应属性,避免全局popHandler被覆盖的问题。
  • 编辑页面viewDidDisappear时可主动清空导航控制器的popHandler,避免野指针调用。

内容的提问来源于stack exchange,提问作者Meeshoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 22:06:01