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

Swift开发:点击自定义UITableViewCell中的Collection Cell时如何跳转ViewController

解决嵌套CollectionView点击跳转的问题

嘿,这个场景其实挺典型的——因为你的CollectionView是嵌套在TableViewCell里面的,直接在MainTableViewCell里处理跳转不是个好主意(既违反MVC的职责划分,cell也不该负责导航逻辑)。下面给你两个最常用、最靠谱的实现方案,你可以根据自己的项目情况选:


方案一:代理模式(最推荐,符合iOS设计规范)

代理是iOS里处理组件间通信的标准方式,尤其适合这种嵌套组件的事件传递。步骤如下:

1. 在MainTableViewCell中定义代理协议

首先我们需要声明一个协议,用来定义点击事件的回调方法:

// 定义代理协议,继承AnyObject避免循环引用
protocol MainTableViewCellDelegate: AnyObject {
    // 传递cell和选中的视频数据,方便VC做后续处理
    func mainTableViewCell(_ cell: MainTableViewCell, didSelectVideo video: Video)
}

class MainTableViewCell: UITableViewCell {
    // 声明代理属性,必须用weak修饰,防止循环引用
    weak var delegate: MainTableViewCellDelegate?
    var videos: [Video] = [] // 你原来的数据源数组
    
    // ... 其他已有的代码(比如CollectionView的初始化、约束等)
}

2. 在CollectionView的点击方法中调用代理

在你已有的UICollectionViewDelegate扩展里,实现didSelectItemAt触发代理方法:

extension MainTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
    // ... 你原来的numberOfItemsInSection和cellForItemAt代码
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let selectedVideo = videos[indexPath.item]
        // 调用代理方法,把选中的视频数据传递给VC
        delegate?.mainTableViewCell(self, didSelectVideo: selectedVideo)
    }
}

3. 在ViewController中遵守代理并处理跳转

假设你的TableView所在的ViewController是HomeViewController,让它遵守代理协议并实现回调方法:

class HomeViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, MainTableViewCellDelegate {
    
    // ... 你的TableView初始化、数据源设置等代码
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell", for: indexPath) as! MainTableViewCell
        // 给cell设置代理为当前VC
        cell.delegate = self
        // 给cell设置对应的数据源数组
        cell.videos = yourDataSourceArray[indexPath.row]
        return cell
    }
    
    // 实现代理方法,处理跳转逻辑
    func mainTableViewCell(_ cell: MainTableViewCell, didSelectVideo video: Video) {
        // 创建你要跳转的详情ViewController
        let detailVC = VideoDetailViewController()
        // 把选中的视频数据传递给详情VC
        detailVC.video = video
        // 执行present跳转(如果是导航栈结构,可以用push)
        present(detailVC, animated: true)
        // 导航栈跳转的话用:navigationController?.pushViewController(detailVC, animated: true)
    }
}

方案二:闭包回调(更简洁,适合简单场景)

如果你的交互逻辑比较简单,闭包会是更紧凑的选择,不需要额外定义协议:

1. 在MainTableViewCell中添加闭包属性

class MainTableViewCell: UITableViewCell {
    var videos: [Video] = []
    // 定义闭包属性,用@escaping标记,因为闭包会在cell生命周期外执行
    var onVideoSelected: ((Video) -> Void)?
    
    // ... 其他已有的代码
}

2. 在CollectionView点击方法中触发闭包

extension MainTableViewCell: UICollectionViewDelegate, UICollectionViewDataSource {
    // ... 原有代码
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        let selectedVideo = videos[indexPath.item]
        // 触发闭包,传递选中的视频数据
        onVideoSelected?(selectedVideo)
    }
}

3. 在ViewController中绑定闭包处理跳转

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MainTableViewCell", for: indexPath) as! MainTableViewCell
    cell.videos = yourDataSourceArray[indexPath.row]
    
    // 绑定闭包,处理跳转逻辑
    cell.onVideoSelected = { [weak self] selectedVideo in
        // 用weak self避免循环引用
        guard let self = self else { return }
        let detailVC = VideoDetailViewController()
        detailVC.video = selectedVideo
        self.present(detailVC, animated: true)
    }
    
    return cell
}

小提醒

不管用哪种方案,都不要直接在MainTableViewCell里处理导航逻辑——cell的核心职责是展示数据,导航是ViewController的工作,这样划分职责会让你的代码更清晰、更容易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 05:48:14