UITableViewCell子类错误图像在单元格或旧图像bug

时间:2017-10-24 02:01:09

标签: swift xcode uitableview

所以伙计们,我曾经遇到Massive View Controller问题,特别是在使用UITableView时,现在我正在改变一个旧的应用程序更加模态。之前,我曾经将整个单元格设置为cellForRowAt indexPath。设置标签,下载图像等。

现在我正在使用正确的方法设置UITableViewCell子类。但我遇到了问题,重新使用单元格,在更新/下载新图片的同时离开旧图片,我认为我修复了,但我也注意到它恰好将错误的图像放在错误的单元格然后在进行快速滚动时更新为正确的...

在我做这样的事情之前,确保图像在正确的单元格中更新。就像这样从视图控制器设置整个单元格......

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier")

    cell.title = "Cool title"

    imageLoader.obtainImageWithPath(imagePath: viewModel.image) { (image) in
        // Before assigning the image, check whether the current cell is visible for ensuring that it's right cell
        if let updateCell = tableView.cellForRow(at: indexPath) {
            updateCell.imageView.image = image
        }
    }    
    return cell
}

现在我几乎只有viewcontroller ...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell : RestCell = self.tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! RestCell

    // Pass data to Cell :) clean the mess at the View Controller ;)
    cell.restData = items[indexPath.row]

    return cell
}

UITableViewCell子类我有这个。

class RestCell: UITableViewCell {

    @IBOutlet var img : UIImageView!
    @IBOutlet var lbl : UILabel!
    @IBOutlet var lbl_tipocomida: UILabel!
    @IBOutlet var lbl_provincia: UILabel!
    @IBOutlet var img_orderonline: UIImageView!
    @IBOutlet var img_open: UIImageView!
    @IBOutlet var imgalldelivery: UIImageView!
    @IBOutlet var img_reservasonline: UIImageView!

    // get data and update.
    var restData: RestsModel!  {
        didSet {
            // default img early placeholder set. Eliminates showing old pic in cell reuse
            self.img.image = UIImage(named: "60x60placeholder.png")
            // Update all values func
            updateUI()
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Default image placeholder
       //self.img.image = UIImage(named: "60x60placeholder.png")

    }
    // required init.
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!

        // Color of selected.
        let myCustomSelectionColorView = UIView()
        myCustomSelectionColorView.backgroundColor = UIColor(red: 234.0/255.0, green: 46.0/255.0, blue: 73.0/255.0, alpha: 0.1) //UIColor(netHex:0xFFFF434)
        selectedBackgroundView = myCustomSelectionColorView   
    }   

    fileprivate func updateUI() {

        if (self.restData.image != nil  &&  self.restData.image != "") {
            ImageLoader.sharedLoader.imageForUrl(urlString:self.restData.image, completionHandler:{(image: UIImage?, url: String) in
                self.img.contentMode = UIViewContentMode.scaleAspectFit
                self.img.image = image
            })
        } else {
            self.img.image = UIImage(named: "60x60placeholder.png")
        }

        self.lbl.text = restData.name as String
        self.lbl_provincia.text = restData.provincia as String
        self.lbl_tipocomida.text = restData.tipocomida as String

        // check if has alldelivery enabled, show Alldelivery logo
        if( self.restData.reservaonline == "1") {
            self.img_reservasonline.isHidden = false
            self.img_reservasonline.image = UIImage(named: "icon_reserva_on")

        } else {
            self.img_reservasonline.isHidden = true
            self.img_reservasonline.image = UIImage(named: "icon_reserva_off")
        }

        // check if has orderonline, show ordeonline text
        if ( self.restData.orderonline == "1") {
            self.img_orderonline.isHidden = false
        } else {

            self.img_orderonline.isHidden = true
        }

        // check if has schedule, display if open or close

        if (self.restData.hasSchedule == true) {

            if ( self.restData.openNow == true) {
                self.img_open.image = UIImage(named:"icon_open")
            }  else {
                self.img_open.image = UIImage(named:"icon_close")
            }

            self.img_open.isHidden = false
        } else {

            self.img_open.isHidden = true
        }

    }

}

我在UITableViewVCell子类的图像上调用下载并将其设置在那里。如何确保图像仅设置为正确的单元格

2 个答案:

答案 0 :(得分:2)

由于竞争条件而发生这种情况(这很常见)

根据您当前的解决方案,我会这样做:

  • 重新加载单元格数据时删除上一张图像。加载新版本后,您可以执行self.myUIImage.image = nil之类的操作。
  • 检查下载图像后单元格是否仍然可见:
    • 如果已加载,则添加图像。
    • 如果没有则忽略它。如果您要缓存它,它将在下次要使用时缓存(这将是另一个主题)。

您可能需要检查一些类似的问题:

Images in UITableViewCells are loading wrong

答案 1 :(得分:1)

我建议您使用第三方库来加载包含Kingfisher等网址的图片。它将处理缓存并取消加载。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let data = dataSource[indexPath.row]
    let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier") as! ACell
    cell.update(data)
    return cell
}

细胞看起来像这样。

import Kingfisher
class ACell: UITableViewCell {
    @IBOutlet fileprivate weak var backgroundImageView: UIImageView!

    fileprivate func reset() {
        backgroundImageView.image = nil
    }

    func update(_ data: ATypeOfData) {
        reset()
        let resource = ImageResource(downloadURL: url)
        backgroundImageView.kf.setImage(with: resource)
    }
}

你失败的原因是你误解了重复使用细胞。

let updateCell = tableView.cellForRow(at: indexPath)

updateCell可以是与您要使用的单元格不同的单元格。它可以只是一个重用的随机单元格。如果您确实想要跟踪单元格,则需要设置属性并检查cellForRowAt中的属性是否与图像加载闭包中的属性相同。我真的建议你使用我附带的模式。