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年齢?

EDIT:異なるアプローチ

は、それが細胞内のモデルへの参照を保持するために適切か?正しいMVCアーキテクチャについて考えてみてください。画像をダウンロードする責任は誰にありますか?セル(完全なモデルオブジェクトではなくURLのみに渡す)またはテーブルビューのビューコントローラ(セル内の画像をtableView:cellForRowAt:メソッドで更新する)?

答えて

0
  1. ImageProviderには、基礎となるURLSessionDownloadTaskを取り消す方法を追加します。セルが再利用される直前にこのメソッドを呼び出します。そのためには、セルサブクラスのprepareForReuse()をオーバーライドします。
  2. 再利用が発生するまでにタスクが既に終了する可能性がありますが、DispatchQueue.main.asyncブロックはまだエンキューされており、セルの再利用が行われた後に起動されます。これを軽減するには、完了したタスクのURLをモデルに格納されているURLと照合する必要があります。
+0

ありがとうございました。私は考えています...実際にモデルをセルに入れるのは正しいのですか?それは 'MVC'パターンを破りますよね?私は、モデルをセルに渡してネットワークのダウンロードを処理するようないくつかの例を見てきましたが、そのようなロジックをテーブルビューのビューコントローラに移動する方が適切でしょうか? – AppsDev

+0

@AppsDev私はあなたにあまり厄介なことをすることをお勧めします。アーキテクチャーパターンを厳格に遵守すれば、不明なメリットのために複雑さが増しますが、私はそれを避けています。あなたの例のようなことをやっていることは、この場合はまったく問題ありません。あなたのシステムがどのように構造化されているかによって異なります。あなたの直感に従ってください:) – ivanmoskalev

関連する問題