首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在UICollectionview中如何在滚动过程中停止图像变化?

在UICollectionview中如何在滚动过程中停止图像变化?
EN

Stack Overflow用户
提问于 2018-04-07 10:05:17
回答 1查看 1.2K关注 0票数 2

我使用collectionview显示下载的URL标识图像。这是我的密码:

代码语言:javascript
复制
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)
}

这是我异步下载映像的扩展代码:

代码语言:javascript
复制
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设置为nil来修复它:

代码语言:javascript
复制
cell.objectImageView.image = nil
cell.objectImageView.downloadedFrom(link: urlArray[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)

但不起作用。如何解决这个问题?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-07 10:43:02

设置nil不会完全有帮助。这主要是一个单元重用问题。

图像下载是异步的,这意味着它将在稍后完成。

如果您滚动并在图像下载完成之前重用一个cell,它将设置上一次下载调用/s的映像,从而导致持续的更改,这是绝对有问题的。

您将需要更多的信息来跟踪这一点,以基本上计算完成的下载任务是为imageView,还是已经被重用,在这种情况下,另一个下载任务将设置它。

我们可以通过多种方式这样做,但在下面,我们检查下载开始时的url是否与下载完成时的url相同。

简单的事物,如:

代码语言:javascript
复制
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()
}

您可以优化逻辑以取消以前的下载,但这是解决核心问题的基本解决方案。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49706190

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档