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

我有一个iOS应用程序正在从一个JSON请求从一个MySQL数据库抓取一堆照片URL。 一旦我有这些照片和相关信息,我用它来填充UITableView的数据源。 我想创build一个UIButtons网格,由照片制成,每行4个。 这个当前的代码工作,但它非常慢,我的电话/模拟器冻结了,当我滚动表。 只有几行的表格可以正常工作,但是一旦达到10行或更多行,它就会慢慢下降,并且接近崩溃。 我是iOS和Objective-C的新手,所以我认为在代码中效率低下。 有什么build议么? 谢谢!!

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

这很慢,因为你在tableView:cellForRowAtIndexPath:做了一切。 tableView:cellForRowAtIndexPath:被称为真的,尤其是每次需要在你的tableview中显示一个单元格,其中包括当你滚动你的tableView。 因此这个方法需要很快 ,而且非阻塞(特别是不要做同步下载!)

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

  • 当你的单元格从前一个单元被重用时(看它被“回收”),你不能重做所有的东西,特别是你不能重新添加每个子单元,因为单元格已经存在了,因为它已经被重用了不是一个干净的新的!
  • 相反,当dequeueReusableCellWithIdentifier:返回一个单元格(=一个旧的单元格以前创build,但不再使用,所以你可以“回收”/重用它),你应该只改变不同的细胞。 在你的例子中,通常你只会改变显示的4个图像,但不要重新创buildUIImageView,也不要将它们作为子视图添加(因为这些子视图已经存在),也不会影响目标/操作。
  • 你只需要创buildUIImageView,添加一个目标/动作,设置他们的框架,并添加他们作为一个子视图,当你正在创build一个全新的单元格,使用alloc / initWithReuseIdentifier: / autorelease

此外,你直接从你的tableView:cellForRowAtIndexPath:并且同步添加(这意味着它阻止你的应用程序,直到它完成从网下载图像! 在您的tableView:cellForRowAtIndexPath:例如当您的应用程序被加载时)执行asynchronous下载并将其存储在本地(例如,在NSArray或sthg中),并只在您的tableView:cellForRowAtIndexPath:获取本地已下载的映像tableView:cellForRowAtIndexPath:

如果您是iOS编程的新手,那么您尝试做的事不是最好的想法。 你想要做什么看起来很简单,但它意味着像asynchronous下载,应用程序的MVCdevise的概念,并在您的视图中显示它们之前从模型中的networking预取图像,提供了一种方法来更新下载完成时的tableview以及桌面视图中的单元重用的基本概念。

在继续之前,请阅读 TableView编程指南 。 它详细解释它,真的值得一读。 另请参阅Apple的LazyTableImages示例代码,该代码解释了如何懒惰地加载图像(意味着在需要时asynchronous加载图像),以及解释如何进行数据asynchronous下载的URL加载编程指南 。

如果你想做你所解释的,这些指南和样本是非常值得一读的。 在网上也有很多类的网格视图,其中之一是我的工作( OHGridView ),但是在进一步学习之前,您需要首先了解上面和上述指南中的基本知识。