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

Swift 4中含两种自定义Cell的TableView出现单元格复用问题

嘿,这个问题我之前在做TableView多Cell类型开发的时候也踩过类似的坑,咱们来一步步拆解解决它~

问题核心原因

本质上是TableView的Cell复用机制加上图片加载逻辑的疏漏导致的:

  • 当Section1的顶部Cell滑出屏幕后,会被放进复用池;当你再滑回来时,系统会从复用池取出这个Cell重新配置
  • 如果你的图片加载没有做本地缓存,也没有在复用前处理旧的下载任务,就会触发重复下载
  • 结合你提到的场景,大概率是Section2的Cell占用复用池后,Section1的Cell复用状态没有被正确重置导致的
具体解决步骤

1. 给图片请求加上缓存策略

用Alamofire发起请求时,设置缓存策略优先使用本地缓存,避免重复请求网络:

// 构造带缓存策略的请求
let urlRequest = URLRequest(
    url: imageURL,
    cachePolicy: .returnCacheDataElseLoad, // 有缓存就用缓存,没有再请求网络
    timeoutInterval: 15
)

// 用这个请求发起下载
AF.request(urlRequest).responseData { [weak self] response in
    guard let data = response.data, let image = UIImage(data: data) else { return }
    // 更新UI要切回主线程
    DispatchQueue.main.async {
        cell?.iconImageView.image = image
    }
}

2. 复用Cell时取消旧下载任务+重置状态

在你的Section1自定义Cell里,重写prepareForReuse()方法,取消未完成的下载任务,同时重置图片为占位图,避免旧任务完成后覆盖新内容:

class Section1Cell: UITableViewCell {
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var iconImageView: UIImageView!
    
    // 持有当前Cell的下载任务引用
    var imageDownloadTask: DataRequest?
    
    override func prepareForReuse() {
        super.prepareForReuse()
        // 取消旧的下载任务
        imageDownloadTask?.cancel()
        imageDownloadTask = nil
        // 重置图片为占位图
        iconImageView.image = UIImage(named: "default_placeholder")
    }
}

3. 绑定数据与Cell,加上内存缓存

用NSCache做内存缓存,让滑回的Cell可以直接从内存取图片,不用再走网络:

// 全局或ViewModel里定义内存缓存
let imageMemoryCache = NSCache<NSString, UIImage>()

// 在cellForRowAt里配置Cell时
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Section1Cell", for: indexPath) as! Section1Cell
        let model = yourSection1Data[indexPath.row]
        
        // 先设置文本
        cell.titleLabel.text = model.title
        
        // 先检查内存缓存
        let cacheKey = model.imageURL.absoluteString as NSString
        if let cachedImage = imageMemoryCache.object(forKey: cacheKey) {
            cell.iconImageView.image = cachedImage
            return cell
        }
        
        // 没有缓存再发起下载
        cell.imageDownloadTask = AF.request(model.imageURL).responseData { [weak cell] response in
            guard let data = response.data, let image = UIImage(data: data) else { return }
            // 存入内存缓存
            imageMemoryCache.setObject(image, forKey: cacheKey)
            // 更新UI
            DispatchQueue.main.async {
                cell?.iconImageView.image = image
            }
        }
        return cell
    } else {
        // 配置Section2的Cell
        let cell = tableView.dequeueReusableCell(withIdentifier: "Section2Cell", for: indexPath) as! Section2Cell
        cell.titleLabel.text = "Section 2 Title"
        cell.emptyImageBackground.backgroundColor = .systemBlue
        return cell
    }
}

4. 可选:添加磁盘缓存

如果需要更持久的缓存(比如APP重启后依然有效),可以自己实现磁盘缓存逻辑,把下载的图片存到沙盒里,下次加载时先读磁盘再请求网络。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:26:58