【问题标题】:What's the most efficient way to handle a UIButton Photo Grid in a UITableView?在 UITableView 中处理 UIButton 照片网格的最有效方法是什么?
【发布时间】:2011-09-18 07:07:38
【问题描述】:

我正在开发一个 iOS 应用程序,它通过 JSON 请求从 MySQL 数据库中获取一堆照片 URL。获得这些照片和相关信息后,我将使用它来填充 UITableView 的数据源。我想创建一个由照片组成的 UIButton 网格,每行 4 个。当前的代码有效,但是速度非常慢,当我滚动表格时,我的手机/模拟器立即冻结。只有几行的表格可以正常工作,但是一旦我达到 10 行或更多行,它就会减速并接近崩溃。我是 iOS 和 Objective-c 的新手,所以我假设这是我的代码效率低下。有什么建议?谢谢!!

- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = [indexPath row];
static NSString *CompViewCellIdentifier = @"CompViewCellIdentifier";

UITableViewCell *cell = [tableView
                         dequeueReusableCellWithIdentifier: CompViewCellIdentifier];

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CompViewCellIdentifier] autorelease];
}

// The photo number in the photos array that we'll need to start off with.
NSUInteger photoNumber = (row * 4);

// Assemble the array of all 4 photos we'll need for this table row (for this cell).
NSMutableArray *rowPhotos = [[[NSMutableArray alloc] initWithObjects:[self.photos objectAtIndex:photoNumber], nil] retain];

NSInteger counter = 1;
while ([self.photos count] > photoNumber+counter && counter<4) {
    [rowPhotos addObject:[self.photos objectAtIndex:photoNumber+counter]];
    counter = counter+1;
}

NSLog(@"The rowPhotos array: %@", rowPhotos);

for (int i=0; i<[rowPhotos count]; i++) {

    // Set which photo we're dealing with for this iteration by grabbing it from our rowPhotos array we assembled. Use i as the index.
    NSDictionary *photoRow = [[NSDictionary alloc] initWithDictionary:[rowPhotos objectAtIndex:i]];

    // Get the photo.
    NSString *photoPath = [[NSString alloc] initWithFormat:@"http://localhost/photorious%@", [photoRow objectForKey:@"path"]];
    NSURL *url = [NSURL URLWithString: photoPath];
    [photoPath release];
    UIImage *cellPhoto = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:url]];

    // Figure out the container size and placement.
    int xCoordinate = ((i*70)+8*(i+1));
    CGRect containerRect = CGRectMake(xCoordinate, 0, 70, 70);

    // Create the Button
    UIButton *cellPhotoButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [cellPhotoButton setFrame:containerRect];
    [cellPhotoButton setBackgroundImage:cellPhoto forState:UIControlStateNormal];
    [cellPhotoButton setTag:(NSInteger)[photoRow objectForKey:@"id"]];

    // Add the button to the cell
    [cell.contentView addSubview:cellPhotoButton];

    // Add the action for the button.

    [cellPhotoButton addTarget:self 
                        action:@selector(viewPhoto:)
              forControlEvents:UIControlEventTouchUpInside];

    [cellPhoto release];
}

[rowPhotos release];
return cell;
}

【问题讨论】:

    标签: ios uitableview delegates datasource


    【解决方案1】:

    这很慢,因为您在 tableView:cellForRowAtIndexPath: 中执行所有操作。 tableView:cellForRowAtIndexPath: 被称为非常频繁,尤其是每次需要在表格视图中显示单元格时,包括滚动表格视图时。因此这种方法需要快速,并且是非阻塞的(尤其是不要进行同步下载!)

    此外,您没有正确使用表格视图单元格的可重用性。当您每次为每个单元格重新创建内容(子视图)时,这会大大降低性能。

    • 当您的单元格从前一个单元中重复使用时(将其视为“回收”),您不能重做所有事情,尤其是您不能重新添加每个子视图,因为单元格本身已经存在,因为它已经重复使用,不是全新的!
    • 相反,当dequeueReusableCellWithIdentifier: 返回一个单元格(= 以前创建但不再使用的旧单元格,因此您可以“回收”/重复使用它)时,您应该只更改单元格之间的不同之处。在您的示例中,通常您只会更改显示的 4 张图像,但不要重新创建 UIImageView,既不会将它们添加为子视图(因为这些子视图已经存在),也不会重新影响目标/操作。
    • 当你创建一个全新的单元格时,你只需要创建 UIImageView,添加一个目标/动作,设置它们的框架并将它们添加为子视图,alloc/initWithReuseIdentifier:/autorelease

    此外,您正在从网络直接在您的tableView:cellForRowAtIndexPath: 中获取图像,并且同步添加(这意味着它会阻止您的应用程序,直到它完成从网络下载图像!!)。 而是在您的tableView:cellForRowAtIndexPath: 之前进行异步下载(例如,当您的应用程序被加载时)并将它们存储在本地(例如在 NSArray 或类似的东西中),并且仅在您的 @987654333 中获取本地已下载的图像@。

    如果您是 iOS 编程新手,那么您尝试做的事情并不是最好的主意。您想做的事情可能看起来很简单,但它暗示了异步下载、应用程序的 MVC 设计以及在您的视图中显示它们之前从模型中的网络预取图像等概念,提供了一种在下载完成时更新 tableview 的方法,以及表格视图中单元格重用的基本概念。

    请阅读TableView Programming Guide,然后再继续。它详细解释了它,真的值得一读。 另请参阅 Apple 的 LazyTableImages 示例代码,它解释了如何在 tableview 中延迟加载图像(意味着在需要时异步加载图像),以及解释如何异步下载数据的 URL Loading Programming Guide

    这些指南和示例真的如果你想做你解释的事情,值得一读。网上也有很多课程可以做 Grid Views,其中一个是我的工作 (OHGridView),但是在继续之前,您需要先了解上面和提到的指南中解释的基础知识。

    【讨论】:

    • 很棒的答案,非常感谢。我一定会好好阅读编程指南并查看您的课程。
    猜你喜欢
    • 2010-09-09
    • 2015-08-27
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 2015-02-14
    • 1970-01-01
    • 2010-11-27
    相关资源
    最近更新 更多