2

我有三个不同的细胞。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

4 回答 4

1

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

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

我希望这会帮助你。

于 2013-01-12T18:16:26.157 回答
0

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

这是一个粗略的示例,说明它的外观(假设您有一个 ivar NSMutableArray *_imageViews,使用正确大小的元素进行初始化,并用 nil 填充)。我在这里从头开始编码,但我希望你能明白。顺便说一句,您可以通过插入它来用 nils 填充可变数组[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
}
于 2013-01-12T18:43:06.857 回答
0

我刚刚完成了类似的实现,如果您确保文档目录中的所有图像都已经是正确的大小(200 x 200),那么这将可以正常工作而无需异步加载。

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

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

于 2013-01-12T19:00:16.853 回答
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];

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

因此,与其这样做...

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来帮助防止缓存变得太大。

于 2013-01-12T20:58:41.023 回答