【问题标题】:Caching an Image and UICollectionView缓存图像和 UICollectionView
【发布时间】:2012-11-30 21:48:27
【问题描述】:

我对 Objective-C 还很陌生,所以希望这一切都有意义。我已经从服务器下载了图像,并以collectionView cellForItemAtIndexPath: 方法将它们显示在图像视图中。我面临的问题是图像似乎没有缓存。看起来每次重复使用一个单元格时,都会重新下载来自服务器的相关图像。

在我的 viewDidLoad 方法中,我正在创建一个 NSMutableDictionary:

imageDictionary = [[NSMutableDictionary alloc]initWithCapacity:50.0];

通过阅读文档并查看类似问题的答案,我认为这加上以下代码就足够了。我已经做了几天了,我知道我缺少一些东西或者我没有掌握的概念。

#pragma mark - UICollectionView Data Source
- (NSInteger)collectionView:(UICollectionView *)view numberOfItemsInSection:(NSInteger)section;{
    NSLog(@"Begin retrieving photos");
    return [self.photos count];
}

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

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;{
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];
    cell.imageView.image = nil;

    if (cell.imageView.image == nil) {
    dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);
    dispatch_async(downloadQueue, ^{
        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.photos objectAtIndex:indexPath.row] objectForKey:@"fullimage"]]];
        UIImage *image = [UIImage imageWithData:data];
        [imageDictionary setObject:image forKey:@"Image"];

        dispatch_async(dispatch_get_main_queue(), ^{
            cell.imageView.image = [imageDictionary objectForKey:@"Image"];
            [cell setNeedsDisplay];
        });
    });
    }
    return cell;
}

任何帮助将不胜感激。提前致谢。

【问题讨论】:

  • 看起来您每次都在重新下载图像。 collectionview 不会为您缓存图像。您需要创建自己的缓存字典。查看 NSCache。

标签: ios xcode image caching uicollectionview


【解决方案1】:

@yuf - 再次感谢您的指导。 NSCache 似乎让我得到了我想要的结果。这是正常工作的代码。如果有人有类似的问题,您可以将以下内容与我的原始问题进行比较。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;{
    CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"MY_CELL" forIndexPath:indexPath];

    NSString *imageName = [[self.photos objectAtIndex:indexPath.row] objectForKey:@"fullimage"];
    UIImage *image = [imageCache objectForKey:imageName];

    if(image){

        cell.imageView.image = image;
    }

    else{

    cell.imageView.image = nil;

    dispatch_queue_t downloadQueue = dispatch_queue_create("image downloader", NULL);
    dispatch_async(downloadQueue, ^{

        NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.photos objectAtIndex:indexPath.row] objectForKey:@"fullimage"]]];
        UIImage *image = [UIImage imageWithData:data];

        dispatch_async(dispatch_get_main_queue(), ^{

            cell.imageView.image = image;

        });

        [imageCache setObject:image forKey:imageName];
    });
    }

    return cell;
}

【讨论】:

  • 这并不完全正确,因为如果正确重用单元格,则在加载图像和更新单元格时,该单元格实例可能被用于表示模型中的另一条记录.最好更新缓存,然后调用集合视图 reloadItemsAtIndexPaths: 并获取 cellForItemAtIndexPath 以从缓存中设置图像(如果可见)。
  • 啊,有道理。事实上,我确实遇到了这个问题(只有一次,但我明白你的意思)。谢谢!
  • @Ants,如果你能添加代码,很多人都会受益(包括我)。谢谢。
  • @Satyam 上面的代码几乎是正确的。所有需要更改的是首先检查图像缓存,如果该项目的图像不存在,则调用代码下载它。下载后调用 reloadItemsAtIndexPaths: 并传递该行的 indexPath 以重新加载它。
  • @Ants,奇怪的是即使在使用reloadItemsAtIndexPaths 之后我仍然遇到你提到的问题:(
猜你喜欢
  • 2020-08-24
  • 2016-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多