滚动时每次都会改变异步图像?

时间:2016-05-10 17:46:37

标签: iphone xcode swift uicollectionview

所以我创建了一个iOS应用程序,可以让你浏览Unsplash壁纸,我使用UICollectionView在单元格中加载图像,但每当我滚动图像时,我都会将图像更改返回到另一个图像。

这是代码

(col1, col2, col3)

3 个答案:

答案 0 :(得分:2)

@toddg解决方案是正确的。但是仍然存在重用细胞的问题。

如果在网络呼叫完成之前重新使用该小区,则它会将下载的图像分配给另一个小区。

所以我改变了代码如下。

var imageArray: [UIImage]?
let downloadQueue = dispatch_queue_create("com.donbytyqi.Papers", nil)

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! ImageCollectionViewCell

    if let oldImage: UIImage = imageArray[indexPath.row] {
        cell.imageView.image = oldImage
        return cell
    } else {
        cell.imageView.image = nil;
        downloadImage(indexPath);
    }


    return cell
}

func downloadImage(indexPath: NSIndexPath) {

    dispatch_async(downloadQueue) {

        let imageURL = NSURL(string: "https://unsplash.it/200/300/?random")
        let imageData = NSData(contentsOfURL: imageURL!)

        var image: UIImage?

        if imageData != nil {
            image = UIImage(data: imageData!)
        }

        let cell = self.collectionView .cellForItemAtIndexPath(indexPath) as! ImageCollectionViewCell
        dispatch_async(dispatch_get_main_queue()) {
            cell.imageView.image = image
        }

    }

}

希望这有帮助。

答案 1 :(得分:1)

编辑:发生了两件事:

  1. collectionView.dequeueReusableCellWithReuseIdentifier重复使用已创建的单元格(如果有可用的单元格)。所以你要将你以前的一个单元格出列。

  2. 加载图片的网址每次调用时都会生成一个随机图片。

  3. 因此,当您滚动到集合视图的第一行不在屏幕上的点时,这些单元格将被重用。然后,当您向上滚动时,将使用"https://unsplash.it/200/300/?random"

    中的新随机图像重新创建单元格

    绕过这种方法的一种方法是根据单元格索引保留所有图像的数组。当然,如果你的图像非常大和/或你有一个非常大的集合视图,你可能会耗尽内存。

    看一下我嘲笑过的代码。我还没有确认代码确实有效。

    //instance var to store your images
    var imageArray: [UIImage]?
    
    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! ImageCollectionViewCell
    
        // Check if we have already loaded an image for this cell index
        if let oldImage: UIImage = imageArray[indexPath.row] {
            cell.imageView.image = oldImage
            return cell
        } else {
            // remove the old image, before downloading the new one
            cell.imageView.image = nil
        }
    
    
        let downloadQueue = dispatch_queue_create("com.donbytyqi.Papers", nil)
    
        dispatch_async(downloadQueue) {
    
            let imageURL = NSURL(string: "https://unsplash.it/200/300/?random")
            let imageData = NSData(contentsOfURL: imageURL!)
    
            var image: UIImage?
    
            if imageData != nil {
                image = UIImage(data: imageData!)
    
                // Save image in array so we can access later
                imageArray.insert(image, atIndex: indexPath.row)
            }
    
            dispatch_async(dispatch_get_main_queue()) {
                cell.imageView.image = image
            }
    
        }
    
        return cell
    }
    

答案 2 :(得分:0)

让我解释一下实际发生了什么 当您滚动并返回时,您实际上会看到之前显示的单元格,其中包含先前下载的图像(因为dequeueReusableCellWithReuseIdentifier:),您将继续看到该图像,直到您的新图像无法下载,即执行{{1}行。

所以,你必须做以下事情:

  1. cell.imageView.image = image行之后设置cell.imageView.image = nil,如下所示:

    dequeueReusableCellWithReuseIdentifier:

    这将从imageView删除以前下载的图像,直到新图像下载。

  2. 您应该使用SDWebImageUIImageView+AFNetworking之类的内容来进行具有缓存支持的异步图像下载,因为每次调用您的方法时,都会一次又一次地下载图像而不是缓存图片,这就是浪费交通。

  3. 祝你好运!