UITableView自定义单元格滚动缓慢

时间:2013-01-12 18:09:48

标签: iphone ios objective-c tableview custom-cell

我有三个不同的细胞。 Cell01,Cell02和Cell03。 Cell01必须只出现一次,位于tableview的顶部,其余的02和03必须插值(02,03,02,03(...))。

问题是滚动TableView时有一些“滞后”。我正在从文档文件夹中加载图像,我也正在调整它以不需要太多处理,但它仍然在缓慢滚动。它正在重复使用单元格(我检查了if(!cell))。

这是我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    int row = indexPath.row;

    if (row == 0) {
        Cell01 *cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell01ID"];
        if (!cell) {
            cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:@"Cell01" owner:self options:nil] objectAtIndex:0];
            cell.someLabel.text = @"First";
            cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"mainimage" andSize:CGSizeMake(200, 200)];
        }

    } else if (row % 2 == 0) {
        Cell02 *cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell02ID"];
        if (!cell) {
            cell = (Cell02 *)[[[NSBundle mainBundle] loadNibNamed:@"Cell02" owner:self options:nil] objectAtIndex:0];
            cell.randomLabel.text = @"Second";
            cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"secondimage" andSize:CGSizeMake(200, 200)];
        }
    } else {
        Cell03 *cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell03ID"];
        if (!cell) {
            cell = (Cell03 *)[[[NSBundle mainBundle] loadNibNamed:@"Cell03" owner:self options:nil] objectAtIndex:0];
            cell.anotherLabel.text = @"Third";
            cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];

        }
    }
}


- (UIImage *)imageInDocumentsDirectoryWithName:(NSString *)fileName andSize:(CGSize)size
{    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString* path = [documentsDirectory stringByAppendingPathComponent:fileName];
    UIImage *image = [UIImage imageWithContentsOfFile:path];
    image = [image resizedImageToFitInSize:size scaleIfSmaller:YES];

    return image;
}

知道如何改进这个tableview(并让它滚动得更快)吗?

4 个答案:

答案 0 :(得分:1)

我认为缓慢滚动是由于从文档目录中加载单元格上的图像。从Doc dir获取图像需要一些时间,当你滚动你的表视图时,会创建一个新的单元格并从doc dir加载图像需要一些时间。尝试在单元格上使用延迟加载图像。也可以在不在主线程中的新线程中加载图像..

有一个Apple的示例项目帮助你。 lazy loading table view

我希望这会有所帮助。

答案 1 :(得分:0)

考虑异步加载图像。您可以在可变数组中保留对所有UIImageView的引用,开始在异步块中加载图像,例如使用GCD,然后在加载时更新图像视图。

这是一个粗略的例子,它看起来如何(假设你有一个ivar NSMutableArray *_imageViews,用正确的元素大小初始化,并填充nils)。我在这里编写代码,但我希望你能得到这个想法。顺便说一下,你可以通过插入[NSNull null]来填充nils的可变数组。

我保证如果你正确实现这一点,你会看到滚动速度明显改善:)

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    int row = indexPath.row;
    if (row == 0) {
        Cell01 *cell = nil;
        cell = [tableView dequeueReusableCellWithIdentifier:@"Cell01ID"];
        if (!cell) {
            cell = (Cell01*)[[[NSBundle mainBundle] loadNibNamed:@"Cell01" owner:self options:nil] objectAtIndex:0];
            cell.someLabel.text = @"First";
            [_imageViews replaceObjectAtIndex:row withObject:cell.someImage];
            dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
            dispatch_async(queue, ^{
                UIImage *image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];

                // because UI needs to be updated on the main thread,
                // dispatch yet another block.
                dispatch_async(dispatch_get_main_queue(), ^{
                   UIIMageView *imageView = [_imageViews objectAtIndex:row];
                   ImageView.image = image;
                 });
            });
      }
     // et cetera
}

答案 2 :(得分:0)

我刚刚完成了类似的操作,如果你确保文件目录中的所有图像都已经是正确的大小(200 x 200),那么这将很好地工作,而不必异步加载。

如果您需要更大的图像,则在保存原始文件时生成尺寸正确的缩略图,因为实际需要花费太多处理来调整“真实”图像的大小时间”。

但在这种情况下,您只有三张图片。 如果您只是在调整图像大小并将其重复使用(而不是制作新图像)之后对图像进行缓存,那么它将比此更快

答案 3 :(得分:0)

您当前的实施存在两个潜在的性能问题。第一种是使用NSBundle而不是UINib来加载nib文件。 NSBundle每次从文件系统重新加载nib文件,而UINib读取一次nib文件并将其内容缓存在内存中。由于每次都不需要从文件系统重新读取nib,因此使用UINib实例化对象应该要快几个数量级。

所以不要这样做......

cell = [[[NSBundle mainBundle] loadNibNamed:@"Cell02" owner:self options:nil] objectAtIndex:0];

......这样做:

cell = [UINib loadNibNamed:@"Cell02" owner:self] objectAtIndex:0];

第二个问题是类似的;当前实现每次都从文件系统重新加载相同的图像,而不是将它们缓存在内存中并重用它们。要解决此问题,您可以添加类型为NSArrayNSDictionary的实例变量(取决于您希望如何检索图像),然后在加载图像之前进行检查以查看它是否已存在于集合中。如果没有,请在使用之前加载图像并将其存储在集合中。否则,使用缓存的图像而不是再次加载它。

所以不要这样做......

cell.someImage.image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];

......做这样的事情:

// Note: Consider defining constants for the keys/filenames.

UIImage *image = [self.cachedImages objectForKey:@"thirdimage"];
if (image == nil) {
    image = [self imageInDocumentsDirectoryWithName:@"thirdimage" andSize:CGSizeMake(200, 200)];
    [self.cachedImages setObject:image forKey:@"thirdimage"];
}

cell.someImage.image = image;

如果您需要以这种方式缓存大量图片,请考虑使用NSCache代替NSDictionary来帮助防止缓存过大。