如何为tableview缓存一些东西?

Jon*_*nah 8 iphone caching uitableview

我有一个带有大图像的桌面视图,可以填充单元格,并根据图像大小设置行高.不幸的是,当滚动到下一个单元格时,表格严重抖动.

有人告诉我,如果在将行高度和图像加载到表格之前缓存行高度,我的tableview将滚动得更顺畅.我的所有数据都存储在plist中.

我如何去缓存一些东西?代码是什么样的,它在哪里?

谢谢!

这是我加载图像的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *detailTableViewCellIdentifier = @"Cell";

    DetailTableViewCell *cell = (DetailTableViewCell *) 
        [tableView dequeueReusableCellWithIdentifier:detailTableViewCellIdentifier];

    NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"DetailTableViewCell" owner:self options:nil];
    for(id currentObject in nib)
    {
        cell = (DetailTableViewCell *)currentObject;
    }
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSString *Path = [[NSBundle mainBundle] bundlePath];
    NSString *MainImagePath = [Path stringByAppendingPathComponent:([[appDelegate.sectionsDelegateDict objectAtIndex:indexPath.section] objectForKey:@"MainImage"])];

    cell.mainImage.image = [UIImage imageWithContentsOfFile:MainImagePath];

    return cell;
}
Run Code Online (Sandbox Code Playgroud)

我也使用以下方法计算行高:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    AppDelegate *appDelegate = (DrillDownAppAppDelegate *)[[UIApplication sharedApplication] delegate];
    NSString *Path = [[NSBundle mainBundle] bundlePath];
    NSString *MainImagePath = [Path stringByAppendingPathComponent:([[appDelegate.sectionsDelegateDict objectAtIndex:indexPath.section] objectForKey:@"MainImage"])];
    UIImage *imageForHeight = [UIImage  imageWithContentsOfFile:MainImagePath]; 
    imageHeight = CGImageGetHeight(imageForHeight.CGImage);  
    return imageHeight;
}
Run Code Online (Sandbox Code Playgroud)

编辑:这是下面的最终代码.

#define PHOTO_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 static NSString *CellIdentifier = @"Photo";

 UIImageView *photo;
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

 AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
 UIImage *theImage = [UIImage imageNamed:[[appDelegate.sectionsDelegateDict objectAtIndex:indexPath.section] objectForKey:@"MainImage"]];

 imageHeight = CGImageGetHeight(theImage.CGImage);
 imageWidth = CGImageGetWidth(theImage.CGImage);

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    photo = [[[UIImageView alloc] initWithFrame:CGRectMake(0, 0, imageWidth, imageHeight)] autorelease];
    photo.tag = PHOTO_TAG;
    [cell addSubview:photo];
   } else {
    photo = (UIImageView *) [cell viewWithTag:PHOTO_TAG];
    [photo setFrame:CGRectMake(0, 0, imageWidth, imageHeight)];
   }

 photo.image = theImage;
 return cell;
 }
Run Code Online (Sandbox Code Playgroud)

Rob*_*ier 16

缓存不是tableview性能的灵丹妙药.缓存只有在计算成本很高的情况下才有价值,您可以避免计算它.另一方面,如果您在UITableViewCell中只有太多的视图,那么缓存对您无效.如果您的行高度都相同,则无需缓存.如果您使用+[UIImage imageNamed:],则系统已经为您缓存了图像.

UITableViewCells最常见的一阶问题是在其中放置太多子视图.你是如何构建你的细胞的?您是否花时间研究表视图编程指南,特别是仔细查看表视图单元?理解本文档将为您节省更多的悲伤.

编辑:(基于上面的代码)

首先,你正在获取一个可重复使用的单元格,然后立即扔掉它,读取一个NIB并迭代所有顶层对象寻找一个单元格(一个看起来几乎就像你刚扔掉的那个单元格).然后你计算出一个字符串,用于打开文件并读取内容.每次UITableView想要一个新的单元格时都会这样做.你会一遍又一遍地为同一行做这件事.

然后,当UITableView想要知道高度时,再次从磁盘读取图像.并且每次UITableView请求时都会这样做(并且它可能会多次询问同一行,但它会尝试对此进行优化).

您应该首先阅读上面链接的UITableView编程指南.希望能帮助很多.当你这样做时,你应该考虑以下事项:

  • 您表示此单元格中只有一个图像视图.你真的需要一个NIB吗?如果您坚持使用NIB(并且在某些情况下有理由使用它们),请阅读编程指南,了解如何实现基于NIB的单元.您应该使用IBOutlet,而不是尝试迭代顶级对象.

  • +[UIImage imageNamed:]将自动查找Resources目录中的文件,而无需计算bundle的路径.它还会自动为您缓存这些图像.

  • 重点-dequeueReusableCellWithIdentifier:是获取UITableView不再使用的单元格,并且您可以重新配置而不是创建新单元格.你在叫它,但是你马上把它丢掉了.您应该检查它是否返回nil,并且只在NIB中加载它.否则,您只需要更改图像.再次阅读编程指南; 它有很多这方面的例子.只要确保你真的想要了解-dequeueReusableCellWithIdentifier:正在做什么,并且不要将它视为你在程序中此时输入的内容.


Pau*_*nge 5

如果你确实需要缓存高度,我做了类似的事情(显示"文章"对象的单元格的缓存高度 - 文章可能是几个子类中的一个):

+ (CGFloat) heightForArticle: (Article*) article atWidth: (CGFloat) width {

    static NSCache* heightCache = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        heightCache = [NSCache new];
    });

    NSAssert(heightCache, @"Height cache must exist");

    NSString* key = @"unique"; //Create a unique key here
    NSNumber* cachedValue = [heightCache objectForKey: key];
    if( cachedValue ) 
        return [cachedValue floatValue];
    else {
        CGFloat height = 40;//Perform presumably large height calculation here

        [heightCache setObject: [NSNumber numberWithFloat: height] forKey: key];

        return height;
    }
}
Run Code Online (Sandbox Code Playgroud)