首页 > 解决方案 > UITableView (Swift 4) 中的奇怪缓存问题

问题描述

我的应用程序有一个非常奇怪的问题,我能想到的只是它是某种缓存问题。基本上,当我滚动时UITableView,显示的缩略图会为同一行重新加载多次,通常每次使用不同的图像,然后最终到达正确的图像。

这里有一个简短(20 秒)的屏幕截图:https ://youtu.be/oa04mlOgMeQ

一旦加载,应用程序应该缓存这些图像,并且图像被命名为匹配奖励代码(并且名称在 JSON 文件中)。我无法弄清楚它为什么这样做。

编辑:这是我的 cellForRowAt 代码:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cellIdentifier = "BonusListViewCell"
        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? BonusListViewCell else {
            fatalError("The dequeued cell is not an instance of BonusListViewCell.")
        }
        // let bonus = bonuses[indexPath.row]
        let bonus: JsonFile.JsonBonuses
        if isFiltering() {
            bonus = filteredBonuses[indexPath.row]
        } else {
            bonus = bonuses[indexPath.row]
        }

        let urlString = "http://tourofhonor.com/appimages/"+(bonus.imageName)
        let url = URL(string: urlString)
        cell.primaryImage.downloadedFrom(url: url!)
        cell.nameLabel.text = bonus.name.capitalized
        cell.bonusCodeLabel.text = bonus.bonusCode.localizedUppercase
        cell.categoryLabel.text = bonus.category
        cell.valueLabel.text = "\(bonus.value)"
        cell.cityLabel.text = "\(bonus.city.capitalized),"
        cell.stateLabel.text = bonus.state.localizedUppercase

        return cell
    }

这是我的downloadedFrom功能:

extension UIImageView {
    func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
        contentMode = mode
        URLSession.shared.dataTask(with: url) { data, response, error in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil,
                let image = UIImage(data: data)
                else { return }
            DispatchQueue.main.async() {
                self.image = image
            }
            }.resume()
    }
    func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
        guard let url = URL(string: link) else { return }
        downloadedFrom(url: url, contentMode: mode)
    }
}

我的 UITableViewCell 代码是:

import UIKit

class BonusListViewCell: UITableViewCell {

    //MARK: Properties
    @IBOutlet weak var bonusCodeLabel: UILabel!
    @IBOutlet weak var categoryLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var valueLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var stateLabel: UILabel!
    @IBOutlet weak var flavorText: UITextView!
    @IBOutlet weak var primaryImage: UIImageView!

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

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

        // Configure the view for the selected state
    }

}

标签: iosswift

解决方案


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cellIdentifier = "BonusListViewCell"
    guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? BonusListViewCell else {
        fatalError("The dequeued cell is not an instance of BonusListViewCell.")
    }
    // let bonus = bonuses[indexPath.row]
    let bonus: JsonFile.JsonBonuses
    if isFiltering() {
        bonus = filteredBonuses[indexPath.row]
    } else {
        bonus = bonuses[indexPath.row]
    }

    let urlString = "http://tourofhonor.com/appimages/"+(bonus.imageName)
    let url = URL(string: urlString)

    //set image url
    cell.imageUrl = URL(string: images[indexPath.row])

    cell.nameLabel.text = bonus.name.capitalized
    cell.bonusCodeLabel.text = bonus.bonusCode.localizedUppercase
    cell.categoryLabel.text = bonus.category
    cell.valueLabel.text = "\(bonus.value)"
    cell.cityLabel.text = "\(bonus.city.capitalized),"
    cell.stateLabel.text = bonus.state.localizedUppercase

    return cell
}

在你的牢房里

import UIKit

class BonusListViewCell: UITableViewCell {

    //MARK: Properties
    @IBOutlet weak var bonusCodeLabel: UILabel!
    @IBOutlet weak var categoryLabel: UILabel!
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var valueLabel: UILabel!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var stateLabel: UILabel!
    @IBOutlet weak var flavorText: UITextView!
    @IBOutlet weak var primaryImage: UIImageView!
    @IBOutlet weak var activity: UIActivityIndicatorView!

    var imageUrl: URL? {
        didSet {
            loadImage()
        }
    }
    var task: URLSessionDataTask?

    override func awakeFromNib() {
        super.awakeFromNib()
        clean()
    }

    func loadImage() {

        //you need cancel previous task
        task?.cancel()

        clean()
        guard let imageUrl = imageUrl else {
            return
        }
        activity.startAnimating()
        task = URLSession.shared.dataTask(with: imageUrl) { [weak self] data, response, error in
            DispatchQueue.main.async {
                self?.activity.stopAnimating()
                if error == nil, let data = data {
                    self?.primaryImage.image = UIImage(data: data)
                }
            }
        }
        task?.resume()
    }

    func clean() {
        primaryImage.image = nil
    }
}

但最好使用AlamofireSDWebImage之类的库


推荐阅读