json - 从 TableView 中的 JSON 数据下载可重复使用的单元格或错误的异步图像

标签 json swift uitableview grand-central-dispatch

我有一个从 API 下载 JSON 数据并将其设置在表格 View 单元格中的应用程序。在某些时候,通过在随机单元格图像中向上/向下滚动,在它具有正确的图像之前可能会自行更改几次。文本数据没有任何问题。起初我以为问题是单元格的可重用性,所以我需要在实际设置新图像之前销毁数据。所以我将 TableViewCell 的这种方法添加到 cellForRowAt 路径以在设置单元格之前销毁数据:

func destroyCellData() {

    self.newsImageView.image = nil
    self.newsTitleLabel.text = nil
    self.tagLabel.text = nil
}

然后是设置单元格的实际方法:

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

    guard let cell = tableView.dequeueReusableCell(withIdentifier: "newscell") as? NewsTableViewCell else {

        print("No such cell")
        exit(14)
    }

    cell.loadingImageIndicator.startAnimating()

    let data = dataManager.getData()

    let dataToInsert = data[indexPath.row]
    cell.destroyCellData()
    cell.setDataToCell(with: dataToInsert)

    return cell
}

方法 setDataToCell 是:

func setDataToCell(newsObject: jsonNews) {

        self.newsTitleLabel.text = newsObject.title
        self.tagLabel.text = newsObject.tag

        let url = newsObject.imageURL
        self.newsImageView.loadImageUsingCacheWithURLString(url, placeholder: UIImage(named: "ViewPlaceholder"), indicator: loadingImageIndicator)

}

最后我在单元格中异步加载图像:

let imageCache = NSCache<NSString, UIImage>()

extension UIImageView {

func loadImageUsingCacheWithURLString(_ URLString: String, placeholder: UIImage?, indicator: UIActivityIndicatorView? = nil) {

    self.image = nil

    if let cachedImage = imageCache.object(forKey: NSString(string: URLString)) {

        self.image = cachedImage
        indicator?.stopAnimating()
        return

    }

    guard let encodedString = URLString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {

        print("Error Loading URL")
        return
    }

    if let url = URL(string: encodedString) {

        URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in

            if error != nil {

                print("ERROR LOADING IMAGES FROM URL: \(String(describing: error))")

                OperationManager.UI {

                    self.image = placeholder
                    indicator?.stopAnimating()
                }

                return
            }

                if let data = data {

                    if let downloadedImage = UIImage(data: data) {

                            print(URLString)
                            imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))

                        OperationManager.UI {

                            self.image = downloadedImage
                            indicator?.stopAnimating()
                    }
                }
            }
        }).resume()
    }
}

所以我的问题是 - 问题出在我下载和设置图像的方法上,还是出在单元的可重用性上?如果可能的话,给我一个更合适的方法来将图像设置为单元格的提示。提前致谢

最佳答案

如果没有您的代码,我怀疑您的问题可能与可重用单元格和异步图像下载有关。这样一来,当您重新加载单元格时,它会启动一个数据任务来下载图像,如果第二个任务开始下载不同的图像,则第一个任务不会发生任何事情。

例如,假设您的第一张图片为 100MB,可重复使用单元格的第二张图片为 1KB。希望 1KB 下载速度更快。这是流程

  1. 带有 image1 的称重传感器
  2. 开始下载image1
  3. 带有 image2 的称重传感器
  4. 开始下载image2
  5. 完成image2的下载
  6. 将单元格图像设置为image2
  7. 完成下载 image1
  8. 将单元格图像设置为image1

由于image2已经设置好,image1的数据下载任务已经完成,cell在显示image2后会更新显示image1,从而显示错误的图片。

要解决您的问题,您需要以某种方式取消第一个操作,或者更确切地说,如果不再显示该数据,则不更新 ImageView 。有很多方法可以做到这一点。一种解决方案是在您的单元格上创建图像 url 的属性,并在下载完成后确认其正确的 url,如果正确,则更新 ImageView 。

func setDataToCell(newsObject: jsonNews) {
    // Your other code
    self.imageURL = newsObject.imageURL
}

// loadImageUsingCacheWithURLString
if let downloadedImage = UIImage(data: data) {

    print(URLString)
    imageCache.setObject(downloadedImage, forKey: NSString(string: URLString))

    OperationManager.UI {
        if url.absoluteString == self.imageURL {
            self.image = downloadedImage
            indicator?.stopAnimating()
        } 
    }
}

注意:没有测试任何这段代码,而是直接从我的脑海中写出来的。它可能有错误。

综上所述,我建议使用第三方图像缓存系统,如 AlamofireImage或人们评论过的其他人之一。

关于json - 从 TableView 中的 JSON 数据下载可重复使用的单元格或错误的异步图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46207630/

相关文章:

javascript - Ember : Underscore model name in JSON while saving model

ios - 如何将 "Open in.."函数添加到自定义 UIWebview?

ios - NSFastEnumerationIteration.member Swift 3

ios - 动态更改 UITableViewCell 高度 - Swift 4

javascript - 如何将 'select' 选项正确绑定(bind)到 API 调用?

arrays - SWIFT 可解码数据传输

ios - 使用 UIButton 文本作为文本输入 - Swift

Xcode swift : My unwind segue doesn't add to my tableView

ios - Swift - 自定义 SectionIndexTitles 在 Tableview 中不起作用

java - 如何让 Jackson 在自定义反序列化器中反序列化嵌套对象