0

Je télécharge une image par cellule que je dois afficher dans un UITableView en appelant une tâche de réseau asynchrone. Ceci est dans la classe UIViewController de la table:Téléchargement et affichage des images dans la cellule appropriée

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 
} 

Et voici 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 
} 
} 

Et 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) 
    } 
}) 
} 
} 

Puisque les cellules peuvent être dynamiquement dequeued et réutilisés et le téléchargement est asynchrone et ensuite une image peut être réutilisée sur chaque cellule en faisant défiler, suis-je de cette façon en veillant à ce que chaque cellule montre toujours son im correspondant âge?

EDIT: Approche différente

Est-il approprié de conserver une référence au modèle dans la cellule? Penser à une architecture correcte MVC. Qui devrait être responsable du téléchargement des images? La cellule (en lui passant uniquement l'URL au lieu de l'objet de modèle complet) ou le contrôleur de vue de la vue de la table (mise à jour de l'image dans la cellule dans sa méthode tableView:cellForRowAt:)?

Répondre

0
  1. Ajouter une méthode à votre ImageProvider qui vous permettra d'annuler l'URLSessionDownloadTask sous-jacent. Appelez cette méthode lorsque la cellule est sur le point d'être réutilisée. Pour cela, remplacez prepareForReuse() dans votre sous-classe de cellule.
  2. Il est possible que la tâche soit déjà terminée au moment de la réutilisation, mais le bloc DispatchQueue.main.async est toujours en file d'attente et sera déclenché après la réutilisation de la cellule. Pour atténuer cela, vous devez vérifier l'URL de la tâche terminée par rapport à l'URL stockée dans votre modèle.
+0

Merci. Je pense ... est-il correct d'avoir le modèle dans la cellule? Cela casse le modèle 'MVC', non? J'ai vu des exemples comme ça, en passant le modèle à la cellule et en gérant le téléchargement du réseau, mais serait-il plus approprié de déplacer cette logique vers le contrôleur de vue de la table? – AppsDev

+0

@AppsDev Je vous conseille de faire la chose qui vous semble moins gênant. Si l'adhésion stricte à la structure architecturale vous fait ajouter de la complexité pour un avantage peu clair, je dirais qu'il faut l'éviter. Faire des choses comme dans votre exemple peut parfaitement se passer dans ce cas. Cela dépend de la structure de votre système. Suivez vos sentiments intestinaux :) – ivanmoskalev