在 UITableView 中滚动时图片混合 Swift

Pictures getting Mixed when scrolling in UITable View Swift

我的程序中有一个带有 dequeueReusableCells 的 UITable 视图 我应该从服务器加载几张图片并在幻灯片放映中显示它们

我有一个自定义单元格,在配置每个单元格时,我在 DispatchQueue.global(qos: .userInitiated).async 中下载图像,在 DispatchQueue.main.async 中,我将下载的图片添加到幻灯片图像中

但是当我开始滚动一些不应该有任何图片的单元格时,有另一个单元格的重复图片

你知道是什么原因造成的吗?!

我在每个单元格中使用 swift 和 ImageSlideShow pod 来放映幻灯片

这是我的部分代码:

在我的新闻单元格中 class 我有以下获取图片的部分:

class NewsCell: UITableViewCell{

    @IBOutlet weak var Images: ImageSlideshow!
    @IBOutlet weak var SubjectLbl: UILabel!
    @IBOutlet weak var NewsBodyLbl: UILabel!

    func configureCell(news: OneNews) {


        self.SubjectLbl.text = news.Subject
        self.NewsBodyLbl.text =  news.Content



        if news.ImagesId.count==0{
            self.Images.setImageInputs([ImageSource(image: UIImage(named: "ImagePlaceholderIcon")!)])
        } 
        else{
            for imgId in news.ImagesId {

                let Url = URL(string: "\(BASE_URL)\(NEWS_PATH)/\(imgId)/pictures")
                DispatchQueue.global(qos: .userInitiated).async {

                    let data = try? Data(contentsOf: Url!)

                    DispatchQueue.main.async {

                        if let d = data {
                            let img = UIImage(data: data!)!
                            imageSrc.append(ImageSource(image: img))
                            self.Images.setImageInputs(imageSrc);
                        }
                    }
                }
            }

        }
    self.Images.slideshowInterval = 3

}

这是 cellForRow 方法:

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

    let cell = generalNewsTableView.dequeueReusableCell(withIdentifier: "NewsCell" , for: indexPath) as!  NewsCell

    if let news = NewsInfo.sharedInstance.getGeneralNews(){
        cell.configureCell(news: news[indexPath.row])

    }
    return cell

}

getGeneralNews()是一个getter即returns的新闻数组 所以我在 cellForRowAt 中做的是我在给定的索引路径中获取新闻并用它配置我的单元格。

class NewsInfo {

static var sharedInstance = NewsInfo()

private init(){}

private (set) var generalNews:[OneNews]!{
    didSet{
        NotificationCenter.default.post(name:
            NSNotification.Name(rawValue: "GeneralNewsIsSet"), object: nil)
    }
}
func setGeneralNews(allGeneralNews:[OneNews]){
    self.generalNews = allGeneralNews
}
func getGeneralNews() -> [OneNews]!{
    return self.generalNews
}
}

每条新闻包含一个图片ID数组

这些是我的 OneNews 中的字段 class var 主题:字符串! 变量Content:String! 变种 ImagesId:[Int]!

谢谢!

UITableViewCell 在您滚动时被重复使用。当一个单元格离开屏幕顶部时,它将被重新用于出现在屏幕底部的另一行。

UITableViewCell 有一个方法 prepareForReuse 您可以重写。您可以使用该方法清除 iamgeViews 或任何其他应重置或取消下载图像的状态。

在你的情况下,你可能不应该使用 Data(contentsOf:),因为它没有给你取消它的方法。 URLSessionDataTask 是更好的选择,因为它允许您在请求完成之前取消它。

如果您想尝试使用这个小代码修复,而不覆盖单元格的 prepareForReuse,只需更改配置单元格:

if news.ImagesId.count==0{
    self.Images.setImageInputs([ImageSource(image: UIImage(named: "ImagePlaceholderIcon")!)])
} 
else{
// STUFF
}

self.Images.setImageInputs([ImageSource(image: UIImage(named: "ImagePlaceholderIcon")!)]) 

if news.ImagesId.count > 0{
// STUFF
}

因此即使重复使用,每个单元格都将以 placeholderIcon 开头

你可以尝试这样的事情。这段代码的主要思想是给出一个唯一的数字来检查单元格是否被重复使用。

  • 我重命名了您代码中的许多属性,因为非类型的大写标识符使代码难以阅读。您不能只替换原始 NewsCell.
  • 的整个定义
  • 原始定义中没有 imageSrc 的声明。我认为这是一个局部变量。如果它是一个全局变量,它可能会导致其他问题,你应该避免。

(标有###的重要行。)

class NewsCell: UITableViewCell {

    @IBOutlet weak var images: ImageSlideshow!
    @IBOutlet weak var subjectLbl: UILabel!
    @IBOutlet weak var newsBodyLbl: UILabel!

    //### An instance property, which holds a unique value for each cellForRowAt call
    var uniqueNum: UInt32 = 0

    func configureCell(news: OneNews) {
        self.subjectLbl.text = news.subject
        self.newsBodyLbl.text =  news.content


        let refNum = arc4random() //### The output from `arc4random()` is very probably unique.
        self.uniqueNum = refNum //### Assign a unique number to check if this cell is reused
        if news.imagesId.count==0 {
            self.images.setImageInputs([ImageSource(image: UIImage(named: "ImagePlaceholderIcon")!)])
        } else {
            var imageSrc: [ImageSource] = [] //###
            for imgId in news.imagesId {

                let Url = URL(string: "\(BASE_URL)\(NEWS_PATH)/\(imgId)/pictures")
                DispatchQueue.global(qos: .userInitiated).async {

                    let data = try? Data(contentsOf: Url!)

                    DispatchQueue.main.async {
                        //### At this point `self` may be reused, so check its `uniqueNum` is the same as `refNum`
                        if self.uniqueNum == refNum, let d = data {
                            let img = UIImage(data: d)!
                            imageSrc.append(ImageSource(image: img))
                            self.images.setImageInputs(imageSrc)
                        }
                    }
                }
            }
        }
        self.images.slideshowInterval = 3
    }
}

请记住,图像的顺序可能与您 OneNewsimagesId 的顺序不同(如 Duncan C 的评论所述)。

请尝试。