繁体   English   中英

带有自定义单元格的UITableView缓慢滚动

[英]UITableView with custom cell scrolling slowly

我有三个不同的单元格。 Cell01,Cell02和Cell03。 Cell01必须只出现一次,在表格视图的顶部,其余的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(并使它滚动更快)?

我认为缓慢滚动是由于从文档目录将图像加载到单元格上。 从Doc目录中获取图像需要花费一些时间,每当您滚动到表格视图时,都会创建一个新单元格并从Doc目录中加载图像,这需要一些时间。 尝试在单元格上使用图像的延迟加载。 还要在新线程而不是主线程中加载图像。

苹果有一个示例项目可以帮助您。 延迟加载表视图

希望对您有帮助。

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

这是一个大概的外观示例(假设您有一个ivar NSMutableArray *_imageViews ,并使用正确的元素大小进行了初始化,并用nil填充)。 我是从臀部开始编码的,但是希望您能理解。 顺便说一句,您可以通过将[NSNull null]插入可变数组来填充[NSNull null]

我保证,如果正确实现此功能,滚动速度将得到显着改善:)

- (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
}

我刚刚完成了类似的工作,如果您确保documents目录中的所有图像都已经是正确的尺寸(200 x 200),则可以正常工作而不必异步加载。

如果需要更大的图像,则在保存原始文件时会生成正确大小的缩略图,因为它实际上需要过多的处理才能实时调整图像大小。

但是在这种情况下,您只有三个图像。 如果仅在调整图像大小后缓存图像并继续重复使用(而不是制作新图像),那么它的速度甚至会更快

当前的实现存在两个潜在的性能问题。 首先是使用NSBundle而不是UINib来加载nib文件。 每次NSBundle从文件系统重新加载nib文件,而UINib会一次读取nib文件并将其内容缓存在内存中。 由于不需要每次都从文件系统中重新读取nib,因此使用UINib实例化对象应该快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来帮助防止缓存过大。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM