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

如何从UITableViewCell获取对应的ViewController引用?

嗨,这个场景我太熟了!之前做列表页的时候经常需要从cell里触发弹窗,给你分享几个实用的方案:

方法一:代理模式(最推荐,解耦性好)

这是iOS开发里最规范的解耦方式,通过定义协议让cell和ViewController通信,完全避免直接依赖。

首先在你的自定义Cell里定义代理协议:

import UIKit

// 定义代理协议
protocol CustomTableViewCellDelegate: AnyObject {
    func cellDidRequestAlert(_ cell: CustomTableViewCell)
}

class CustomTableViewCell: UITableViewCell {
    // 代理属性必须用weak,避免循环引用
    weak var delegate: CustomTableViewCellDelegate?
    
    // 假设是按钮点击触发弹窗需求
    @IBAction func triggerAlertBtnTapped(_ sender: UIButton) {
        // 通知代理执行弹窗逻辑
        delegate?.cellDidRequestAlert(self)
    }
}

然后在ViewController里遵守协议并实现方法:

class YourViewController: UIViewController, CustomTableViewCellDelegate {
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
        // 设置cell的代理为当前VC
        cell.delegate = self
        return cell
    }
    
    // 实现代理方法,在这里显示弹窗
    func cellDidRequestAlert(_ cell: CustomTableViewCell) {
        let alert = UIAlertController(title: "提示", message: "从Cell触发的弹窗", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        present(alert, animated: true)
    }
}

方法二:闭包(Block)实现,写法更简洁

如果觉得代理写起来有点繁琐,闭包是更轻量化的选择,直接把弹窗逻辑“传递”给cell。

在自定义Cell里定义闭包属性:

class CustomTableViewCell: UITableViewCell {
    // 定义闭包类型,用于触发弹窗
    var onTriggerAlert: (() -> Void)?
    
    @IBAction func triggerAlertBtnTapped(_ sender: UIButton) {
        // 调用闭包执行弹窗逻辑
        onTriggerAlert?()
    }
}

然后在ViewController配置cell时传入闭包:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomTableViewCell
    
    // 传入闭包,注意用[weak self]避免循环引用
    cell.onTriggerAlert = { [weak self] in
        guard let self = self else { return }
        let alert = UIAlertController(title: "提示", message: "通过闭包触发的弹窗", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        self.present(alert, animated: true)
    }
    
    return cell
}

方法三:遍历响应链获取ViewController(应急用,不推荐长期依赖)

这个方法可以直接从cell的响应链里往上找ViewController,写法简单但耦合性很高,如果后续视图层级变化(比如cell被嵌套在其他容器里),可能会失效,只适合临时应急。

先给UIView写个扩展:

extension UIView {
    func findParentViewController() -> UIViewController? {
        var currentResponder = self.next
        // 遍历响应链,直到找到ViewController实例
        while currentResponder != nil {
            if let vc = currentResponder as? UIViewController {
                return vc
            }
            currentResponder = currentResponder?.next
        }
        return nil
    }
}

然后在Cell里直接调用:

@IBAction func triggerAlertBtnTapped(_ sender: UIButton) {
    if let parentVC = self.findParentViewController() {
        let alert = UIAlertController(title: "提示", message: "通过响应链获取VC触发的弹窗", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "确定", style: .default))
        parentVC.present(alert, animated: true)
    }
}

小提醒

不管用代理还是闭包,都一定要用weak修饰对ViewController的引用,不然很容易造成循环引用导致内存泄漏哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:40:09