首页 > 解决方案 > 从 CellForRowAt 调用的函数更新 TableViewCell 中的 ImageView

问题描述

我尝试更新一个 ImageView 女巫是我的 TableViewCell 的一部分。每个单元格都有其他国家,对于每个单元格,我想下载该县的国旗并将其显示在单元格的 ImageView 中,所以我使用 CellForRowAt,准备好单元格的国家并调用一个下载国旗图像的函数. 但我不明白,如何更新 Cell 中的 ImageView ......

这是我的代码:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell

        // Configure the cell...
        
        let stock = stocks[indexPath.row]
        
        // Image downloading

        loadCountryImage(country: stock.country)
                
        return cell
    }
    
    func loadCountryImage(country: String) {
        
        let url = "https://www.countryflags.io/\(country)/shiny/24.png"
        guard let imageURL = URL(string: url) else {
            print("no URL found")
            return
        }
        
        let session = URLSession.shared
        session.dataTask(with: imageURL) { imageData, _, _ in
            let image = UIImage(data: imageData!)
            
            
        }.resume()

那么现在图片下载成功了,但是如何在cell的imageView中获取呢?

来自德国的亲切问候!亚尼克

标签: iosswiftuitableview

解决方案


简短的回答是将单元格传递给,loadCountryImage以便您可以从数据任务更新闭包中的单元格图像。此更新需要分派到主队列。

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell

    // Configure the cell...
        
    let stock = stocks[indexPath.row]

    cell.imageView.image = somePlaceholderImage
        
        // Image downloading

    loadCountryImage(country: stock.country, in: cell)
                
    return cell
}
    
func loadCountryImage(country: String, in cell:CustomCell) {
        
    let url = "https://www.countryflags.io/\(country)/shiny/24.png"
    guard let imageURL = URL(string: url) else {
        print("no URL found")
        return
    }
        
    let session = URLSession.shared
    session.dataTask(with: imageURL) { imageData, _, _ in
       guard let data = imageData, let image = UIImage(data: data) else { 
           return
       }
 
       DispatchQueue.main.async {
           cell.imageView.image = image
       }     
    }.resume()
}

长答案是您应该考虑缓存,并且由于单元格被重用,当表格视图滚动时会发生什么?您可能会获取过期的图像。一种方法是将国家/地区存储在单元格中并检查闭包以查看它是否仍然是您在设置图像之前所期望的。

您可以使用UITableviewDatasourcePrefetchingNSCache


var imageCache = NSCache<NSString,UIImage>()

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CustomCell

    // Configure the cell...
        
    let stock = stocks[indexPath.row]

    cell.imageView.image = somePlaceholderImage
    cell.country = stock.country
        
        // Image downloading

    loadCountryImage(country: stock.country, in: cell)
                
    return cell
}

func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath]) {
    for indexPath in indexPaths {
        let stock = stocks[indexPath.row]
        if self.cache.object(forKey: stock.country) == nil {
            self.loadCountryImage(country: stock.country, in: nil)
        }
    }
}
    
func loadCountryImage(country: String, in cell:CustomCell?) {

    if let image = self.imageCache.object(forKey: country) {
         cell?.imageView.image = image
         return
    }
        
    let url = "https://www.countryflags.io/\(country)/shiny/24.png"
    guard let imageURL = URL(string: url) else {
        print("no URL found")
        return
    }
        
    let session = URLSession.shared
    session.dataTask(with: imageURL) { imageData, _, _ in
       guard let data = imageData, let image = UIImage(data: data) else { 
           return
       }
 
       DispatchQueue.main.async {
           self.imageCache.setObject(image, forKey: country)
           if cell?.country == country {
               cell?.imageView.image = image
           } 
       }     
    }.resume()
}

一个更好的答案可能是查看像 SDWebImage 或 Kingfisher 这样的框架,它们为您做了很多这样的事情。


推荐阅读