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

使用Delegate&Protocol实现TableView按钮控制CollectionView显隐报错

Delegate调用错误:Cannot convert value of type 'InsideTableViewCell.Type' to expected argument type 'InsideTableViewCell'

问题场景

我尝试通过TableView单元格内的勾选按钮控制单元格内CollectionView的显示与隐藏,用Delegate和Protocol实现,但在按钮点击事件里调用代理方法时,出现了标题里的类型转换错误。我的代码步骤如下:

  1. 在TableViewCell类中定义协议:
protocol CustomCellDelegate{ 
    func selectCollectionView(cell: InsideTableViewCell) 
}
  1. 在主ViewController中声明代理变量:
var delegate: CustomCellDelegate? 
  1. 主ViewController遵循CustomCellDelegate协议:
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UICollectionViewDelegate,UICollectionViewDataSource,CustomCellDelegate 
  1. 在cellForRowAtIndexPath方法中给单元格按钮添加点击事件并设置代理:
cell.checkButton.addTarget(self, action: #selector(self.selectCheck(_:)), for: .touchUpInside) 
cell.delegate = self 
  1. 按钮点击的Selector函数:
@objc func selectCheck(_ sender: UIButton) { 
    if sender.isSelected { 
        sender.isSelected = false 
        print("Check 1") 
        delegate?.selectCollectionView(cell: InsideTableViewCell) // 这里报错!
    } else{ 
        print("Check 2") 
        sender.isSelected = true 
    } 
}
  1. 实现的代理方法:
func selectCollectionView(cell: InsideTableViewCell) { 
    cell.clCollectionView.isHidden = true 
}

错误原因分析

你遇到的报错核心问题是:在调用delegate?.selectCollectionView(cell: InsideTableViewCell)时,你传入的是InsideTableViewCell这个类的类型(Type),但代理方法需要的是这个类的一个具体实例对象(Instance),两者类型不匹配,所以编译器报错。

另外,你的代理设置逻辑还有个小问题:代理属性应该定义在InsideTableViewCell类中,而不是主ViewController里——因为是Cell需要通知VC做操作,所以Cell要持有代理(VC)的引用,而不是反过来。

修正步骤

1. 修正Cell类中的代理定义

首先,在InsideTableViewCell里正确定义协议和代理属性(注意要加weak避免循环引用):

// 协议要继承AnyObject,这样才能用weak修饰代理
protocol CustomCellDelegate: AnyObject {
    func selectCollectionView(cell: InsideTableViewCell)
}

class InsideTableViewCell: UITableViewCell {
    // 声明代理属性,必须是weak
    weak var delegate: CustomCellDelegate?
    
    // 你的控件:勾选按钮、CollectionView
    @IBOutlet weak var checkButton: UIButton!
    @IBOutlet weak var clCollectionView: UICollectionView!
}

2. 移除ViewController中多余的代理变量

删掉主VC里的var delegate: CustomCellDelegate?——这个变量完全没必要,因为VC本身就是代理的实现者,Cell会持有VC的引用作为代理。

3. 修正按钮点击事件,传入正确的Cell实例

在selectCheck方法里,我们需要获取到当前点击按钮所在的那个InsideTableViewCell实例,而不是传类类型。可以通过递归查找父视图的方式,比直接用superview更可靠:

@objc func selectCheck(_ sender: UIButton) {
    // 切换按钮选中状态
    sender.isSelected.toggle()
    
    // 打印日志
    print(sender.isSelected ? "Check 2" : "Check 1")
    
    // 找到当前按钮所在的Cell实例
    guard let cell = findParentCell(of: sender) else {
        return
    }
    
    // 调用代理方法,传入正确的Cell实例
    cell.delegate?.selectCollectionView(cell: cell)
}

// 递归查找按钮所在的Cell
private func findParentCell(of view: UIView) -> InsideTableViewCell? {
    if let cell = view as? InsideTableViewCell {
        return cell
    }
    return view.superview.flatMap { findParentCell(of: $0) }
}

4. 优化代理方法的逻辑

让代理方法根据按钮的选中状态动态切换CollectionView的显示隐藏,而不是固定设为隐藏:

func selectCollectionView(cell: InsideTableViewCell) {
    // 按钮选中时显示CollectionView,未选中时隐藏
    cell.clCollectionView.isHidden = !cell.checkButton.isSelected
}

验证效果

现在运行代码,点击单元格的勾选按钮,就能正确触发代理方法,控制对应单元格内的CollectionView显示或隐藏了,也不会再出现类型转换的错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:00:00