collectionview
ダウンロードしたURLで識別された画像を表示するために使用しています。これは私のコードです:
var urlArray = ["url1", "url2", ..., "urln"]
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "myCell, for: indexPath) as? MyCell
cell.objectImageView.downloadedFrom(link: urlArray[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)
}
これは、画像を非同期でダウンロードする私の拡張コードです。
func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
contentMode = mode
URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
DispatchQueue.main.async() {
self.image = image
}
}.resume()
}
func downloadedFrom(link: String, contentMode mode: UIViewContentMode = .scaleAspectFit) {
guard let url = URL(string: link) else { return }
downloadedFrom(url: url, contentMode: mode)
}
collectionview
画像をスクロールすると、各セルの画像が連続的に変化しています。メソッドにロードimageview
するnil
前にをに設定して修正しようとしましたcellForItemAt
:
cell.objectImageView.image = nil
cell.objectImageView.downloadedFrom(link: urlArray[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)
しかし、それは機能しません。この問題を解決するにはどうすればよいですか?
設定nil
は完全には役に立ちません。これは主にセルの再利用の問題です。
イメージのダウンロードは非同期です。つまり、後で完了します。画像のダウンロードが完了する前に
スクロールしてacell
を再利用すると、前のダウンロード呼び出しの画像が設定されるため、継続的な変更が発生し、間違いなくグリッチが発生します。
完了したダウンロードタスクが、imageView
または再利用されたものであるかどうかを基本的に把握するには、これを追跡するための追加情報が必要になります。その場合、別のダウンロードタスクがそれを設定します。
これはさまざまな方法で実行できますが、以下では、ダウンロードの開始時のURLがダウンロードの完了時のURLと同じであるかどうかを確認します。
次のような単純なもの:
func downloadedFrom(url: URL, contentMode mode: UIViewContentMode = .scaleAspectFit) {
/*
1.
strUniqueIdentifier_Initial will be the url that caused the download to start.
A copy of this will be accessible in the closure later.
Also, we bind this to the imageView for case handling in the closure.
*/
let strUniqueIdentifier_Initial = url.absoluteString
self.accessibilityLabel = strUniqueIdentifier_Initial
contentMode = mode
let dataTask = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
let data = data, error == nil,
let image = UIImage(data: data)
else { return }
/*
2.
strUniqueIdentifier_Initial is a copy of the url from the start of the function
strUniqueIdentifier_Current is the url of the current imageView as we use self
so if the imageView is reused, this method will be called on it again and at
that time it it's binded url string will be for the latest download call
If there's mismatch then the imageView was reused
*/
let strUniqueIdentifier_Current = self.accessibilityLabel
if strUniqueIdentifier_Initial != strUniqueIdentifier_Current {
//previous download task so ignore
return
}
DispatchQueue.main.async() {
self.image = image
}
}
dataTask.resume()
}
ロジックを最適化して以前のダウンロードをキャンセルすることができますが、これはコアの問題に対する基本的な解決策です。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加