UICollectionViewController 会暂时显示错误的图像,然后刷新到正确的图像

UICollectionViewController would show me a wrong image for a moment and then refresh to the right one

我正在根据 JSON 响应创建集合视图。 Json 响应具有高分辨率图像和 2000 年左右的图像数量。由于数据来自第三方,我无法控制图像大小。

实施:

JSON 样本:

{
    "imagelist": [
        {
            "largeImage": "https://amazingphotos/01.jpg"
        },
        {
            "largeImage": "https://amazingphotos/02.jpg"
        },
}

正在访问 UICollectionViewController 中的 JSON:

Alamofire.request(.GET, dataURL)
            .responseJSON { _, _, result in
                if var json:JSON = JSON(result.value!){
                self.imageURLs = json["imagelist"].arrayValue
                self.collectionView?.reloadData()
                }
        }

在 cellForItemAtIndexPath 中,我将 URL 传递给单元格而不是图像本身。

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("imageCell", forIndexPath: indexPath) as! CollectionViewCell
        cell.imageData = imageURLs[indexPath.row]

在自定义 Cell 中,我只是这样做:

var imageData:SwiftyJSON.JSON?{
        didSet{
            self.setup() 
        }
    }

    func setup(){
        if let imageURLString = self.imageData?["largeImage"]{
            let imageURL = NSURL(string: imageURLString.stringValue)
            self.imageThumbnail.hnk_setImageFromURL(imageURL!)
        }

问题:当我加载集合视图时,它会正确显示图像,一旦我开始滚动,它就会在新单元格上显示以前的图像几秒钟,然后刷新。

我曾多次使用集合视图,但从未处理过如此多的数据。请指教。 TIA

编辑:
如果您还没有实现缓存,将图像 URL 而不是图像传递给单元格通常不是一个好习惯。
您可以尝试通过以下方法之一解决此问题:

  1. nilprepareForReuse 中取出 imageView 的图像(按照建议 通过 ChrisH)
  2. 一张一张地下载图像并将它们存储在一个数组中。下载图像后,调用: collectionView.reloadItemsAtIndexPaths(indexPaths); 那个 特定的细胞。
  3. 重构代码并实现图像缓存。

如果您在实现图像缓存方面需要帮助(使用 NSCache),遵循 Objective-C 代码可能会给您一个想法:

@interface MBGalleryViewController ()
{
    NSArray* imageUrls;  // array of image urls
    NSCache* cache;
}
@end

@implementation MBGalleryViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    cache = [[NSCache alloc] init]; // initialize cache
}

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    return 1;
}

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return [imageUrls count];
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString* identifier = @"Cell";

    MyCollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier
                                                                           forIndexPath:indexPath];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {

        UIImage* image = [cache objectForKey:@(indexPath.item)];  // retrieve image for this indexPath.item
        if (!image) {  // will be true if is not yet cached
            image = [imageDownloader downloadImageWithURL:imageUrls[indexPath.item]];  // download image from somewhere
            [cache setObject:image forKey:@(indexPath.item)];   // cache image for this indexPath.item
        }

        dispatch_sync(dispatch_get_main_queue(), ^(void) {
            cell.imageView.image = image;  // set image
        });
    });

    return cell;
}

@end

原版Post
我过去也遇到过类似的问题。
这是因为 cellForItemAtIndexPath 在图像实际下载之前被调用,或者可能是因为图像未在主队列中更新。
此问题的解决方法是在 UICollectionViewCell.
中为您的 ImageView 设置默认图像 也可以尝试像这样设置图像:
dispatch_async(dispatch_get_main_queue()) { cell.imageView.image = imageURLs[indexPath.row]; }
希望这对您有所帮助!

您在滚动集合视图时看到的是一个重复使用的单元格,其中包含以前使用的图像。 UICollectionViewCell 有一个 prepareForReuse 函数,您可以使用该函数将任何子视图设置回默认状态。

override func prepareForReuse() {

    myImageView.image = nil

    super.prepareForReuse()
}