在 UITableView 中缓存图像
Posted
技术标签:
【中文标题】在 UITableView 中缓存图像【英文标题】:Caching images in UITableView 【发布时间】:2012-03-23 02:09:54 【问题描述】:我正在将图片加载到与单元格文本对应的表格视图中,因此每个图像都不同。当用户向下滚动时,ios 必须手动从 SSD 重新加载每个图像,因此滚动非常不稳定。如何缓存图像或防止需要重新创建表格视图单元格?其他人已经通过使用imageNamed:
解决了他们的问题,因为 iOS 会自动缓存您的图像,但我是从文档目录加载图像,而不是从应用程序包加载图像。我该怎么办?谢谢。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
// Return the number of sections.
return 1;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
// Return the number of rows in the section.
return [issues count];
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
// Set up the cell...
NSDictionary *dic = [self.issues objectAtIndex:indexPath.row];
cell.text = [dic objectForKey:@"Date"];
cell.imageView.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/issues/%@/cover.png", documentsDirectory, [dic objectForKey:@"Directory Name"]]];
return cell;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
return 150;
【问题讨论】:
检查 UIImageLoader。它完全符合您的要求,只需添加两个文件到 xcode。它也非常容易理解,并且 repo 中有两个很棒的示例。 github.com/gngrwzrd/UIImageLoader 【参考方案1】:那组字典是你的模型,所以它是一个自然的地方。棘手的部分是使您的模型可变。您可以使模型在类中可变,或者在缓存图像时跳过箍。我推荐前者,但在此处编码以匹配您现有的代码...
- (UIImage *)imageForIndexPath:(NSIndexPath *)indexPath
NSDictionary *dic = [self.issues objectAtIndex:indexPath.row];
UIImage *image = [dic valueForKey:@"cached_image"];
if (!image)
image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/issues/%@/cover.png", documentsDirectory, [dic objectForKey:@"Directory Name"]]];
NSMutableDictionary *updatedDictionary = [NSMutableDictionary dictionaryWithDictionary:dic];
[updatedDictionary setValue:image forKey:@"cached_image"];
NSMutableArray *updatedIssues = [NSMutableArray arrayWithArray:self.issues];
[updatedIssues replaceObjectAtIndex:indexPath.row withObject:[NSDictionary dictionaryWithDictionary:updatedDictionary]];
self.issues = [NSArray arrayWithArray:updatedIssues];
return image;
第一次滚动列表时会出现波动,之后会变得平滑。如果您不想在视图出现之前进行第一次切割并产生一点延迟,您可以提前遍历模型并强制加载:
for (int i=0; i<self.issues.count; i++)
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
(void)[self imageForIndexPath:indexPath];
最后一件事 - 另一种解决方案是一个可变数组来匹配您的问题数组。这可能很好,但通常情况下,我很高兴我在模型中包含了一些缓存计算。如果您发现自己在其他地方使用了该问题数组,您会很高兴您已经处理了所有图像。
【讨论】:
谢谢,我会尽快尝试!除了复制和粘贴代码之外,我还有什么要做的吗?抱歉,我对 UITableViews 没有太多经验 :) 我想不到。它应该作为第一步。下一步是让你的模型可变,这将简化和加快图像缓存方法中的工作。 @danh self.issues = [NSArray arrayWithArray:self.issues];必须是 self.issues = [NSArray arrayWithArray:updatedIssues];对吗? @OzBoz 你是对的。谢谢。回读,不知道为什么我专注于改变模型。当时,我认为这会阻止 OP 将模型用作图像缓存,但现在我没有看到证据表明这是问题所在(即使在问题的编辑中)。也许这是一个早期的编辑?无论如何,很好的收获。会修正我的答案。【参考方案2】:除了缓存,您还可以考虑使用 Grand Central 调度在后台加载图像。加载单元格后,放置一个 UIActivityIndicator,然后在单独的线程中将其替换为图像。
还可以查看有关图像口吃的相关答案: Non-lazy image loading in iOS
【讨论】:
非常感谢。我正在查看 Grand Central Dispatch 并在这里找到了一个很好的示例项目 (github.com/SlaunchaMan/GCDExample)以上是关于在 UITableView 中缓存图像的主要内容,如果未能解决你的问题,请参考以下文章
关于使用沙盒与缓存进行 UITableView 异步图像下载的建议
在 iOS 的 UITableViewCell 中更新 UIButton 图像时发生冲突