Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift-如何在UICollectionview中滚动期间停止图像更改?_Ios_Swift_Uicollectionview - Fatal编程技术网

Ios Swift-如何在UICollectionview中滚动期间停止图像更改?

Ios Swift-如何在UICollectionview中滚动期间停止图像更改?,ios,swift,uicollectionview,Ios,Swift,Uicollectionview,我正在使用collectionview显示下载的URL标识图像。这是我的代码: var urlArray = ["url1", "url2", ..., "urln"] func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReu

我正在使用
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
时,每个单元格中的图像都在不断变化。在加载到
cellForItemAt
方法之前,我尝试通过将
imageview
设置为
nil
来修复它:

cell.objectImageView.image = nil
cell.objectImageView.downloadedFrom(link: urlArray[indexPath.row], contentMode: UIViewContentMode.scaleAspectFit)

但它不起作用。如何解决此问题?

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

映像下载是异步的,这意味着它将在以后完成。
如果您在图像下载完成之前滚动并重新使用
单元格
,它将设置上一次下载调用的图像,从而导致您的持续更改,这肯定是错误的

您需要额外的信息来跟踪这一点,以确定完成的下载任务是否用于
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()
}


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

从代码中可以清楚地看出,您希望加载与单元对应的映像,但您的问题可能是单元重用。那么,你能详细说明一下你所说的不断变化是什么意思吗?为什么要将图像设置为零?在我的问题中不断更改是,滚动时每个单元格中的图像将更改为urlArray中的另一个图像,并且在collectionview中的位置错误。我认为如果将图像设置为nil,它将清除imageView并重新下载图像以将正确的图像设置到单元格中。设置
nil
不会完全有帮助。这主要是一个单元重用问题。映像下载是异步的,这意味着它将在以后完成。如果在图像下载完成之前滚动并重新使用某个单元格,它将设置上一次下载调用的图像。您需要其他信息来跟踪此信息。让我为你写点东西。谢谢@staticVoidMan,我正在等待你的解决方案:)为什么不使用SDWebImage进行异步图像下载?它最适合于支持缓存的异步映像下载程序,因为UIImageViewI也遇到了同样的问题,您的答案很有效。此外,我想知道解决这个问题的其他方法,因为你提到你知道其他方法,或者至少提供我可以参考的任何链接。谢谢你,班迪亚。很乐意帮忙。这里的基本思想是确保完成的下载任务对于cell/imageView仍然有效。如果它被重新用于另一个下载任务,那么上一个任务应该被取消或忽略。@BandiA。在本例中,我们使用
self.accessibilityLabel
作为一种技巧,将一些信息存储在
imageView
实例中,因此我们不会对其进行子类化。除非您的应用程序认真对待此图像上的可访问性标签,否则只需支付少量费用。@BandiA。更好的方法是子类化
UIImageView
,并使用您自己的变量来记住url,甚至可能保留下载请求的引用,以便您可以取消请求以节省带宽。@BandiA。或您可以修改
downloadedFrom(url:contentMode:)
以获得如下的完成处理程序:
downloadedFrom(url:url,uu.completion:@escaping(UIImage?->Void)->DataTask
。返回的
DataTask
可以存储在单元格中,如果重复使用此单元格,则在启动新的
DataTask
之前暂停/取消该
DataTask。此外,在完成闭包中,您最终确定是否应设置图像。这样就不需要对self.accessibilityLabel进行hack或子类化。