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

为什么UITableView滚动后自定义cell会出现内容显示错误?

问题原因
  • Cell复用异步请求未处理:UITableView会复用滑出屏幕的Cell,你在configure方法中发起的图片异步请求没有做取消逻辑,当Cell被复用到新位置后,旧请求返回仍然会修改当前Cell的内容,造成图文错配。
  • 文本赋值逻辑错误:你将名称、地址文本的赋值放在了图片请求成功的回调中,如果图片请求失败、请求响应慢,会出现文本不显示/延迟显示,甚至旧请求返回的文本直接覆盖当前Cell正确文本的问题。
  • 复用重置逻辑不全:prepareForReuse方法中没有清空地址文本、没有取消未完成的图片请求,残留的旧请求和旧内容会干扰新赋值的内容。
修复方案

修改自定义Cell的代码如下:

import UIKit

class SearchTableViewCell: UITableViewCell {

    static let identifier = "SearchTableViewCell"

    @IBOutlet var loader: UIActivityIndicatorView!
    @IBOutlet var nameLabel: UILabel!
    @IBOutlet var addressLabel: UILabel!
    @IBOutlet var locationImageView: UIImageView!
    var currentIndexPath: IndexPath?
    // 新增属性:存储当前正在加载的图片url,用于回调校验
    var currentLoadUrl: String?
    // 新增属性:存储当前图片加载任务,用于复用前取消
    var imageLoadTask: URLSessionDataTask?

    override func awakeFromNib() {
        super.awakeFromNib()
        
        nameLabel.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 25)
        nameLabel.textColor = .white
        nameLabel.numberOfLines = 1
        
        addressLabel.font = UIFont(name: Settings.shared.MAIN_APP_FONT_BOLD, size: 15)
        addressLabel.textColor = .white
        addressLabel.numberOfLines = 0
        
        locationImageView.clipsToBounds = true
        locationImageView.layer.cornerRadius = 8.0
        locationImageView.contentMode = .scaleAspectFill
    }

    func configure(with urlString: String, name: String, address: String, station: String) {
        // 优先赋值文本,无需等待图片加载
        nameLabel.text = name
        addressLabel.text = address
        
        loader.startAnimating()
        loader.isHidden = false
        // 先清空旧图片,避免显示上一次复用的内容
        locationImageView.image = nil
        
        // 取消上一次未完成的图片加载任务
        imageLoadTask?.cancel()
        
        guard let url = URL(string: urlString) else {
            loader.stopAnimating()
            loader.isHidden = true
            return
        }
        // 记录当前要加载的url
        currentLoadUrl = urlString
        
        let task = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard let self = self else { return }
            // 校验当前加载的url是否和Cell最新要加载的url一致,避免复用错乱
            guard self.currentLoadUrl == urlString,
                  let data = data, error == nil,
                  let locationImage = UIImage(data: data) else {
                DispatchQueue.main.async {
                    self.loader.stopAnimating()
                    self.loader.isHidden = true
                }
                return
            }
            
            DispatchQueue.main.async {
                self.locationImageView.image = locationImage
                self.loader.stopAnimating()
                self.loader.isHidden = true
            }
        }
        // 存储当前加载任务
        imageLoadTask = task
        task.resume()
    }

    static func nib() -> UINib {
        return UINib(nibName: "SearchTableViewCell", bundle: nil)
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        // 复用前取消未完成的请求
        imageLoadTask?.cancel()
        imageLoadTask = nil
        currentLoadUrl = nil
        // 清空所有旧内容
        nameLabel.text = nil
        addressLabel.text = nil
        locationImageView.image = nil
        currentIndexPath = nil
        loader.stopAnimating()
        loader.isHidden = true
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 07:18:04