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

UITableViewCell嵌套UICollectionView分页加载图片重复问题求助

问题描述

我实现了一个UITableView,每个UITableViewCell中嵌套了一个UICollectionView用于横向轮播图片。每个UITableViewCell通过ViewModel配置,ViewModel包含嵌套UICollectionView所需的imageURL数组数据源。首次加载一切正常,但加载第二页数据后,第二页的UITableViewCell图片与第一页重复,不过CollectionView下方的PageControl页数与imageURL数组数量匹配,显示正确。

测试场景:首次加载5条UITableView数据,前2条的嵌套UICollectionView各有1张图片;加载第二页的2条数据后,这2条的图片与第一页前2条重复,但PageControl页数正确。

注:不建议使用prepareForReuse()重置内容,除非别无选择。


相关代码

UITableView的cellForRow方法

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: DataTableViewCell.id, for: indexPath) as! DataTableViewCell
    cell.delegate = self
    cell.configureWith(viewModel.getViewModelAt(indexPath.row))
  
    return cell
}

嵌套UICollectionView的cellForItem方法

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    if indexPath.row == 0 {
      let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CensoredDataCollectionViewCell.id, for: indexPath) as! CensoredDataCollectionViewCell
      cell.setRemoteImage(with: viewModel.photoGalleryURLStrings[0])
      
      return cell
    }
    
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImageCollectionViewCell.id, for: indexPath) as! ImageCollectionViewCell
    let imageURLString = viewModel.photoGalleryURLStrings[indexPath.row - 1]
    cell.setRemoteImage(with: imageURLString)

    return cell
}

setRemoteImage方法用于从服务器加载图片到cell的ImageView,indexPath.row - 1是因为UICollectionView首项为特殊单元格。

滚动加载下一页的代码

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    if indexPath.row == viewModel.dataCount - 1 {
      tableViewFooterLoadingWheel.startAnimating()
      viewModel.downloadData { [weak self] moreData in

        if moreData {
          DispatchQueue.main.async {
            self?.tableView.reloadData()
          }
        }
        
        DispatchQueue.main.async {
          self?.tableViewFooterLoadingWheel.stopAnimating()
        }
      }
    }
}

网络请求成功追加数据的代码

case .success(let result):
  strongSelf.data.append(contentsOf: result.results)
        
  if let next = result.next {
    strongSelf.dataURL = next
  } else {
    strongSelf.dataURL = nil
  }
 
  completion(true)

UITableViewCell的configureWith方法

func configureWith(_ viewModel: dataViewModel) {
  self.dataViewModel = viewModel
  
  loadingWheel.startAnimating()
  avatarImageView.loadImageFromURL(dataViewModel.avatarImageURLString) { [weak self] in
    DispatchQueue.main.async {
      self?.loadingWheel.stopAnimating()
    }
  }
  statusLabel.text = dataViewModel.status
  createdAtLabel.text = dataViewModel.created
  photoGalleryPageControl.numberOfPages = dataViewModel.photoGalleryURLStrings.count
  likesCountLabel.text = "\(dataViewModel.likeCount)"
  
  likesButton.isSelected = dataViewModel.isLiked

  commentsCountLabel.text = dataViewModel.commentCount
}

问题原因与解决方案

核心问题

UITableViewCell复用后,嵌套的UICollectionView没有重新加载数据。configureWith方法仅更新了PageControl的页数,但未触发UICollectionView的数据源刷新,导致复用的CollectionView仍显示之前cell的图片数据。

解决步骤

在configureWith方法末尾添加UICollectionView的刷新代码:

func configureWith(_ viewModel: dataViewModel) {
  self.dataViewModel = viewModel
  
  // 原有代码保持不变...
  
  commentsCountLabel.text = dataViewModel.commentCount
  
  // 刷新嵌套的CollectionView,加载当前ViewModel对应的图片数据
  photoGalleryCollectionView.reloadData()
}

补充说明

  • 调用reloadData()会让CollectionView重新执行cellForItemAt方法,基于当前cell绑定的ViewModel获取正确的图片URL,彻底避免复用旧数据的问题。
  • 无需使用prepareForReuse(),因为配置cell时主动刷新了CollectionView,确保每次复用都加载最新的数据源。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 19:10:01