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_
相关产品推荐
相关产品推荐

