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

iOS开发:默认返回按钮触发Unwind Segue传值的方案咨询

解决默认返回按钮的数据回传与未保存提示问题

这个问题我之前做iOS项目的时候也碰到过,默认的UINavigationBar返回按钮确实没法直接关联unwind segue,不过有几个实用的解决方案,既能保留和系统几乎一致的导航体验,又能解决数据回传或者未保存修改的问题:

方案一:自定义返回按钮(模仿系统样式)

这种方式的好处是完全可控,能直接绑定unwind segue,而且可以做到和系统返回按钮几乎一模一样的样式。具体步骤如下:

  • 在第二个VC的viewDidLoad中创建自定义返回按钮,隐藏系统默认的返回按钮
  • 给自定义按钮添加点击事件,在事件里处理数据传递或未保存提示,再触发unwind segue或者直接返回

代码示例:

class SecondViewController: UIViewController {
    var hasUnsavedChanges = false
    var newDetails = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        // 创建模仿系统样式的返回按钮,标题用上一个VC的标题或默认"Back"
        let backButtonTitle = navigationController?.viewControllers.first?.title ?? "Back"
        let backButton = UIBarButtonItem(title: backButtonTitle, 
                                         style: .plain, 
                                         target: self, 
                                         action: #selector(backButtonTapped))
        // 设置和系统一致的返回箭头(可选,需适配系统图标)
        navigationController?.navigationBar.backIndicatorImage = UIImage(systemName: "arrow.left")
        navigationController?.navigationBar.backIndicatorTransitionMaskImage = UIImage(systemName: "arrow.left")
        
        navigationItem.leftBarButtonItem = backButton
        navigationItem.hidesBackButton = true // 隐藏系统默认返回按钮
    }

    @objc private func backButtonTapped() {
        if hasUnsavedChanges {
            // 弹出未保存提示框
            let alert = UIAlertController(title: "未保存的修改", 
                                          message: "离开会丢失当前修改,是否保存后返回?", 
                                          preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "保存并返回", style: .default) { [weak self] _ in
                self?.performSegue(withIdentifier: "unwindToFirstVC", sender: self)
            })
            alert.addAction(UIAlertAction(title: "不保存返回", style: .destructive) { [weak self] _ in
                self?.navigationController?.popViewController(animated: true)
            })
            alert.addAction(UIAlertAction(title: "取消", style: .cancel))
            present(alert, animated: true)
        } else {
            // 无修改直接返回,也可以触发unwind传递空数据
            navigationController?.popViewController(animated: true)
        }
    }
}

方案二:拦截系统返回按钮事件(利用导航控制器代理)

如果你不想自定义按钮,想完全保留系统返回按钮的样式和交互,可以通过UINavigationControllerDelegate来拦截返回按钮的点击事件:

  • 让第二个VC成为导航控制器的代理
  • 实现navigationBar(_:shouldPopItem:)方法,在里面处理未保存提示或数据回传

代码示例:

class SecondViewController: UIViewController, UINavigationControllerDelegate {
    var hasUnsavedChanges = false
    var newDetails = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        navigationController?.delegate = self
    }

    // 拦截导航栏返回按钮点击
    func navigationBar(_ navigationBar: UINavigationBar, shouldPop item: UINavigationItem) -> Bool {
        guard hasUnsavedChanges else {
            return true // 无修改,允许系统默认返回
        }

        let alert = UIAlertController(title: "未保存的修改", 
                                      message: "是否要保存当前修改?", 
                                      preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "保存并返回", style: .default) { [weak self] _ in
            self?.performSegue(withIdentifier: "unwindToFirstVC", sender: self)
            navigationBar.popItem(animated: true)
        })
        alert.addAction(UIAlertAction(title: "不保存返回", style: .destructive) { _ in
            navigationBar.popItem(animated: true)
        })
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        present(alert, animated: true)
        return false // 阻止系统默认的返回行为
    }

    // 页面消失时恢复代理,避免影响其他VC的导航
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        if isMovingFromParent {
            navigationController?.delegate = nil
        }
    }
}

方案三:利用闭包在返回时自动传递数据

如果不需要弹出提示,只是想在用户点击返回按钮时自动把修改的数据传递给第一个VC,可以用闭包的方式,这种方式不需要unwind segue,更轻量:

  • 在第二个VC中定义一个闭包属性
  • 在第一个VC跳转时设置闭包的内容
  • 在第二个VC的viewWillDisappear中调用闭包传递数据

代码示例:

// 第二个VC
class SecondViewController: UIViewController {
    var newDetails = ""
    // 定义传递数据的闭包
    var onBack: ((String) -> Void)?

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // 判断是否是返回上一个VC(不是被其他页面push)
        if isMovingFromParent {
            onBack?(newDetails)
        }
    }
}

// 第一个VC
class FirstViewController: UIViewController {
    var details = ""

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let secondVC = segue.destination as? SecondViewController {
            secondVC.newDetails = details
            // 设置闭包,接收返回的数据并更新UI
            secondVC.onBack = { [weak self] updatedDetails in
                self?.details = updatedDetails
                self?.updateDisplayedDetails() // 刷新UI的方法
            }
        }
    }

    private func updateDisplayedDetails() {
        // 更新页面上的详情展示
    }
}

选择建议

  • 如果你需要弹窗提示用户保存修改,方案一或方案二都可以:方案一自定义按钮更直观,方案二完全保留系统样式
  • 如果只是需要静默传递修改后的数据,方案三是最简洁的选择

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:31:39