如何从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
相关产品推荐
相关产品推荐

