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

Swift 4中调用popViewController无响应:点击UITableViewCell返回UIView求助

解决UITableView点击返回并传值的问题

嘿,作为Swift新手遇到这种问题太正常啦,我来帮你一步步捋清楚问题所在,然后搞定它~

首先,你说调用navigationController?.popViewController(animated: true)没效果,大概率是跳转方式的问题,先搞清楚这个核心问题:

为什么pop没效果?

你提到B已经嵌入UINavigationController,并且用show segue从A跳转到B。这里要注意:
如果A本身没有嵌入UINavigationController,那show segue其实是把B的导航控制器以**模态(present)**的方式展示出来的,而不是push到导航栈里。这时候B所在的导航栈里只有它自己,popViewController自然没地方可返回。

你可以在B的viewDidLoad里加一行代码验证:

print(navigationController?.viewControllers ?? [])

如果输出结果里只有B这一个控制器,就说明确实是模态跳转的,这时候你应该用dismiss代替pop:

dismiss(animated: true, completion: nil)

如果想要用pop正常返回,那需要调整跳转逻辑:让A也嵌入UINavigationController,然后直接用show(或push)segue跳转到B本身(而不是跳转到B的导航控制器),这样A和B就处于同一个导航栈里,pop就能顺利回到A了。

搞定数据传递

不管是用pop还是dismiss,要把B的单元格数据传给A,最常用的两种方式是代理模式和闭包回调,我都给你写清楚:

方式一:代理模式(iOS反向传值标准做法)

  1. 在B控制器里定义一个代理协议:
// 替换YourDataType为你实际的数据类型,比如String、自定义Model等
protocol TableViewControllerBDelegate: AnyObject {
    func didSelectCell(with data: YourDataType)
}
  1. 在B里声明一个弱引用的代理属性:
weak var delegate: TableViewControllerBDelegate?
  1. 在单元格点击方法里,先调用代理传递数据,再返回:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // 拿到选中单元格的数据
    let selectedData = yourDataArray[indexPath.row]
    // 通知代理(也就是A控制器)拿到数据
    delegate?.didSelectCell(with: selectedData)
    
    // 根据跳转方式选择返回方法
    navigationController?.popViewController(animated: true)
    // 如果是模态跳转就用下面这句
    // dismiss(animated: true, completion: nil)
}
  1. 在A控制器里,遵守代理协议并实现方法:
extension ViewControllerA: TableViewControllerBDelegate {
    func didSelectCell(with data: YourDataType) {
        // 在这里处理传递过来的数据,比如更新UI、保存到变量等
        print("从B拿到的数据:\(data)")
    }
}
  1. 在A的prepare(for segue:...)方法里设置代理:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    // 记得给segue设置一个唯一的identifier,比如"GoToViewControllerB"
    if segue.identifier == "GoToViewControllerB" {
        var targetVC: TableViewControllerB?
        // 如果是直接跳转到B
        if let vc = segue.destination as? TableViewControllerB {
            targetVC = vc
        }
        // 如果是跳转到B的导航控制器,要先拿到导航的顶层控制器
        else if let navVC = segue.destination as? UINavigationController {
            targetVC = navVC.topViewController as? TableViewControllerB
        }
        // 设置代理
        targetVC?.delegate = self
    }
}

方式二:闭包回调(更简洁的写法)

  1. 在B控制器里声明一个闭包属性:
var onDataSelected: ((YourDataType) -> Void)?
  1. 在单元格点击方法里触发闭包并返回:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let selectedData = yourDataArray[indexPath.row]
    // 触发闭包传递数据
    onDataSelected?(selectedData)
    
    // 选择对应的返回方法
    navigationController?.popViewController(animated: true)
    // dismiss(animated: true, completion: nil)
}
  1. 在A的prepare(for segue:...)里设置闭包:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "GoToViewControllerB" {
        var targetVC: TableViewControllerB?
        if let vc = segue.destination as? TableViewControllerB {
            targetVC = vc
        } else if let navVC = segue.destination as? UINavigationController {
            targetVC = navVC.topViewController as? TableViewControllerB
        }
        // 用weak self避免循环引用
        targetVC?.onDataSelected = { [weak self] data in
            guard let self = self else { return }
            // 处理数据
            print("从B拿到的数据:\(data)")
        }
    }
}

最后再检查一遍

  1. 确认跳转方式和返回方法匹配:push用pop,present用dismiss。
  2. 给segue设置正确的identifier,避免prepare方法里找不到目标控制器。
  3. 数据类型要对应,别把String传给Int类型的参数哦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:37:53