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

UITableView嵌套横向UICollectionView传值typeSelected为空问题

问题原因

两个核心错误导致传值失效:

  • 属性归属类错误:你在tableView(_:cellForRowAt:)中给BTableViewCell实例赋值typeSelected,但该属性、以及依赖它的getDeals查询方法实际定义在内部的BCollectionViewCell类上。外层B类单元格本身不存在你赋值的这个属性,要么是编译时隐式生成了空值属性,要么是传值链路完全断裂,查询时读取到的永远是String()初始化的空字符串。
  • 赋值后未触发查询:即便属性位置正确,仅给属性赋值不会自动执行查询逻辑,getDeals没有调用入口自然不会拉取数据。再加上市Cell复用机制没有处理旧数据、旧请求残留,就算查到数据也可能出现滑动后内容错乱。
修复方案

1. 调整B类单元格的结构

把typeSelected属性、查询方法、结果存储数组都挪到外层BTableViewCell中,通过属性监听器实现赋值即触发查询刷新,不要把控制查询逻辑的属性放在内层CollectionCell上:

class BTableViewCell: UITableViewCell {
    // 连线内部横向滚动的UICollectionView
    @IBOutlet weak var innerCollectionView: UICollectionView!
    // 控制查询类型的属性,用didSet监听赋值动作
    var typeSelected: String = "" {
        didSet {
            // 赋值后先清空旧数据,避免复用显示残留内容
            dealArray.removeAll()
            innerCollectionView.reloadData()
            // 自动触发数据查询
            getDeals { [weak self] in
                guard let self = self else { return }
                self.innerCollectionView.reloadData()
            }
        }
    }
    // 存储当前cell的查询结果
    var dealArray: [PFObject] = []

    override func awakeFromNib() {
        super.awakeFromNib()
        // 内部CollectionView的数据源、代理由当前B类Cell自己管理
        innerCollectionView.dataSource = self
        innerCollectionView.delegate = self
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        // 复用时清空旧数据、取消未完成请求,避免串数据
        dealArray.removeAll()
        PFQuery.cancelAllRequests(forTarget: self)
        innerCollectionView.reloadData()
    }

    // 查询方法移到外层B类Cell中
    func getDeals(_ completionHandler: @escaping () -> Void) {
        let query = PFQuery(className: "Deal")
        query.whereKey("DealType", equalTo: typeSelected)
        query.findObjectsInBackground(block: { [weak self] (objects: [PFObject]?, error: Error?) in
            guard let self = self, let resObjects = objects, error == nil else {
                completionHandler()
                return
            }
            self.dealArray = resObjects
            completionHandler()
        })
    }
}

// MARK: 内部CollectionView数据源实现
extension BTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return dealArray.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BCollectionCell", for: indexPath) as! BCollectionViewCell
        // 这里仅向内层Cell传单条展示数据,不要传查询类型参数
        let currentDeal = dealArray[indexPath.item]
        // 配置Cell展示内容...
        return cell
    }
}

2. 保留外层ViewController的传值逻辑

外层cellForRowAt的B类Cell配置逻辑不需要额外修改,去掉强制解包避免崩溃即可,属性监听器会自动触发后续查询刷新:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row.isMultiple(of: 2) {
        let cell = tableView.dequeueReusableCell(withIdentifier: "A", for: indexPath) as! ATableViewCell
        cell.typeLabel.text = dealTypeArray[indexPath.row].type
        cell.titleLabel.text = dealTypeArray[indexPath.row].title
        cell.selectionStyle = .none
        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "B", for: indexPath) as! BTableViewCell
        cell.selectionStyle = .none
        // 赋值后自动触发didSet逻辑,不需要手动调用查询
        cell.typeSelected = dealTypeArray[indexPath.row].title ?? ""
        return cell
    }
}
优化提示
  • 不要随意对可选值使用强制解包!,用??提供默认值,避免接口返回nil时触发崩溃
  • 嵌套横向滚动列表的模式中,内层列表的数据源、代理由持有它的外层Cell自行管理,不要把逻辑全部抛给顶层ViewController,避免indexPath对应错乱
  • 带异步网络请求的可复用Cell,必须在prepareForReuse中清理旧状态、取消未完成请求,否则快速滑动列表时大概率出现内容串位

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 14:42:33