0

我通过调用异步网络任务,为每个需要在UITableView中显示的单元格下载图像。这是UIViewController类表:在相应的单元格中下载并显示图像

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    guard results.count > 0 else { 
     return UITableViewCell() 
    } 

    let myCell = tableView.dequeueReusableCell(withIdentifier: CustomCell.cellIdentifier, for: indexPath) as! CustomCell 
    let model = results[indexPath.row] 
    myCell.model = model 
    return myCell 
} 

这是CustomCell

class CustomCell: UITableViewCell { 

// Several IBOutlets 

static let cellIdentifier = "myCell" 
let imageProvider = ImageProvider() 

var model: MyModel? { 
willSet { 
    activityIndicator.startAnimating() 
    configureImage(showImage: false, showActivity: true) 
} 
didSet { 
    guard let modelUrlStr = model?.imageUrlStr, let imageUrl = URL(string: modelUrlStr) else { 
     activityIndicator.stopAnimating() 
     configureImage(showImage: false, showActivity: false) 
     return 
    } 

    imageProvider.getImage(imageUrl: imageUrl, completion: {[weak self] (image, error) in 
     DispatchQueue.main.async { 
      guard error == nil else { 
       self?.activityIndicator.stopAnimating() 
       self?.configureImage(showImage: false, showActivity: false) 
       return 
      } 

      self?.imageView.image = image 
      self?.activityIndicator.stopAnimating() 
      self?.configureImage(showCoverImage: true, showActivity: false) 
     } 
    }) 
} 
} 

override func awakeFromNib() { 
super.awakeFromNib() 
configureImage(showCoverImage: false, showActivity: false) 
} 

override func prepareForReuse() { 
super.prepareForReuse() 
model = nil 
} 

private func configureImage(showImage: Bool, showActivity: Bool) { 
// Update image view 
} 
} 

而且ImageProvider

class ImageProvider { 
var imageTask: URLSessionDownloadTask? 

func getImage(imageUrl: URL, completion: @escaping DownloadResult) { 
imageTask?.cancel() 

imageTask = NetworkManager.sharedInstance.getImageInBackground(imageUrl: imageUrl, completion: { (image, error) -> Void in 
    if let error = error { 
     completion(nil, error) 
    } else if let image = image { 
     completion(image, nil) 
    } else { 
     completion(nil, nil) 
    } 
}) 
} 
} 

由于细胞可以动态离队和重复使用和下载是异步的,然后一个图像可以在滚动时在每个单元格上重用,我是这样确保每个单元格总是显示其对应的im年龄?

编辑:不同的方法

是否适当,以保持在细胞模型中的参考?考虑正确的MVC体系结构。谁应该负责下载图像?单元格(仅传递给URL而不是完整的模型对象),或者表视图的视图控制器(更新tableView:cellForRowAt:方法中的单元格中的图像)?

回答

0
  1. 添加一个方法你ImageProvider,将允许您取消底层URLSessionDownloadTask。当单元即将被重用时调用此方法。为此,请在您的单元格子类中覆盖prepareForReuse()
  2. 有可能在任务重新发生时已经完成任务,但DispatchQueue.main.async模块仍然排队,并且会在发生单元重用后触发。为了缓解这种情况,您需要根据存储在模型中的URL检查已完成任务的URL。
+0

谢谢。我在想......实际上在单元中有模型是正确的吗?这打破了MVC模式,对吧?我看过一些例子,像这样做,将模型传递给单元格,并在那里处理网络下载,但将这样的逻辑移动到表视图的视图控制器会更合适吗? – AppsDev

+0

@AppsDev我会建议你做那些让你感觉不那么尴尬的事情。如果严格遵守架构模式会使您为不明确的收益增加复杂性,我会说避免它。在你的例子中完成的东西在这种情况下可能是完全正确的。这取决于你的系统的结构。按照你的直觉感受:) – ivanmoskalev

相关问题