在UITableView中处理UIButton Photo Grid的最有效方法是什么?

时间:2011-06-19 20:30:35

标签: ios uitableview delegates datasource

我有一个iOS应用程序,我正在使用JSON请求从MySQL数据库中获取大量照片URL。一旦我有这些照片和相关信息,我就用它来填充UITableView的数据源。我想创建一个由照片组成的UIButtons网格,每行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;
}

1 个答案:

答案 0 :(得分:4)

这很慢,因为你在tableView:cellForRowAtIndexPath:中做了所有事情。 tableView:cellForRowAtIndexPath:被称为真正的,特别是每次需要在您的tableview中显示一个单元格时,其中包括滚动tableView时的情况。因此,此方法需要快速,并且非阻塞(特别是不要进行同步下载!)

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

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

此外,您正在autorelease直接从网络中获取图像,并且另外同步(这意味着它会阻止您的应用程序直到从网上下载图像!!)。 在tableView:cellForRowAtIndexPath:(例如加载你的应用程序)之前进行异步下载并在本地存储它们(例如在NSArray中,或者类似于sthg),并且仅获取本地已经下载的图像tableView:cellForRowAtIndexPath:

如果您不熟悉iOS编程,那么您尝试做的事情并不是最好的选择。您想要做的事情看似简单,但它意味着异步下载,应用程序的MVC设计以及在您的模型中从网络中预取图像之前的概念,然后在视图中显示它们,提供一种在下载完成后更新tableview的方法,以及tableviews中单元格重用的基本概念。

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

如果您想要解释的话,这些指南和样本真的值得一读。还有很多类在网上做网格视图,其中一个是我的工作(OHGridView),但是你需要先了解上面解释的基础知识,然后再进一步了解上述指南。