如何在TableView内嵌CollectionView点击时调用ViewController方法刷新数据
嘿,这个场景我太熟悉了!要实现嵌套在TableViewCell里的CollectionViewCell点击后,触发父控制器OneStopShopVC的API调用并刷新第二个TableCell,有几种靠谱的方案,我给你一步步拆解:
方案一:代理模式(最推荐,解耦清晰,iOS组件通信标准玩法)
这是iOS开发中最常用的组件间通信方式,逻辑清晰,而且方便后续扩展,步骤如下:
- 给CategoryTableViewCell定义代理协议
在CategoryTableViewCell.swift里创建一个协议,声明点击事件的方法:
import UIKit // 定义代理协议,注意用AnyObject保证只能被类实现 protocol CategoryTableViewCellDelegate: AnyObject { // 可以根据需求传递参数,比如选中的分类数据、索引路径等 func categoryCell(_ cell: CategoryTableViewCell, didSelectCategoryAt indexPath: IndexPath) } class CategoryTableViewCell: UITableViewCell { // 代理属性必须用weak,避免循环引用 weak var delegate: CategoryTableViewCellDelegate? // 假设你已经有了CollectionView的数据源数组 var categories: [YourCategoryModel] = [] // MARK: - UICollectionViewDelegate func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 调用代理方法,把点击事件传递出去 delegate?.categoryCell(self, didSelectCategoryAt: indexPath) } }
- 在OneStopShopVC中实现代理并设置
在OneStopShopVC.swift里,先遵守代理协议,然后在创建cell的时候设置代理:
extension OneStopShopVC: CategoryTableViewCellDelegate { func categoryCell(_ cell: CategoryTableViewCell, didSelectCategoryAt indexPath: IndexPath) { // 这里可以拿到选中的分类数据(如果需要) let selectedCategory = cell.categories[indexPath.item] // 调用你的API方法 searchDataFromFilteredApi() // API请求完成后,刷新第二个TableCell(假设它在section 0的row 1位置) // 局部刷新比全局reloadData()更高效 tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic) } } // 在tableView的cellForRowAt方法里设置代理 extension OneStopShopVC: UITableViewDataSource { func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if indexPath.row == 0 { let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as! CategoryTableViewCell // 设置代理为当前VC cell.delegate = self // 配置cell的数据源 cell.categories = yourCategoryDataArray return cell } else { let cell = tableView.dequeueReusableCell(withIdentifier: "DataTableCell", for: indexPath) as! DataTableCell // 用API返回的数据配置第二个cell cell.configure(with: yourApiResponseData) return cell } } }
方案二:闭包(简洁直观,适合简单场景)
如果不想写代理协议,闭包是更轻量化的选择,代码更紧凑:
- 在CategoryTableViewCell里定义闭包属性
class CategoryTableViewCell: UITableViewCell { // 定义闭包类型,参数可以根据需求调整 var onCategorySelected: ((IndexPath) -> Void)? var categories: [YourCategoryModel] = [] func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 调用闭包,传递点击信息 onCategorySelected?(indexPath) } }
- 在OneStopShopVC中绑定闭包
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if indexPath.row == 0 { let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryTableViewCell", for: indexPath) as! CategoryTableViewCell cell.categories = yourCategoryDataArray // 绑定闭包,注意用[weak self]避免循环引用 cell.onCategorySelected = { [weak self] indexPath in guard let self = self else { return } let selectedCategory = cell.categories[indexPath.item] self.searchDataFromFilteredApi() self.tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic) } return cell } else { // 配置第二个cell let cell = tableView.dequeueReusableCell(withIdentifier: "DataTableCell", for: indexPath) as! DataTableCell cell.configure(with: yourApiResponseData) return cell } }
方案三:通知中心(适合跨多层级,但尽量少用)
如果你的组件层级特别深,或者临时需要快速实现,可以用通知中心,但缺点是代码耦合度高,不好维护,容易出现通知满天飞的情况:
- 在OneStopShopVC中注册通知观察者
override func viewDidLoad() { super.viewDidLoad() // 注册通知,监听分类选中事件 NotificationCenter.default.addObserver( self, selector: #selector(handleCategorySelected), name: NSNotification.Name("CategorySelected"), object: nil ) } @objc private func handleCategorySelected(notification: Notification) { // 从通知的userInfo里获取数据(如果需要) if let indexPath = notification.userInfo?["indexPath"] as? IndexPath { // 调用API并刷新cell searchDataFromFilteredApi() tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic) } } // 记得在页面消失时移除观察者,避免内存泄漏 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self) }
- 在CategoryTableViewCell中发送通知
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 发送通知,携带需要的数据 NotificationCenter.default.post( name: NSNotification.Name("CategorySelected"), object: nil, userInfo: ["indexPath": indexPath] ) }
最后说句心里话
个人最推荐代理模式,因为它的代码结构清晰,适合组件复用,后续扩展也方便;闭包适合简单的小型场景,代码更简洁;通知中心尽量少用,除非是跨多个层级的全局事件,不然很容易让代码变得难以维护。
内容的提问来源于stack exchange,提问作者Rohit
相关产品推荐
相关产品推荐

