2011-06-19 14 views
0

我有一個iOS應用程序,我正在使用JSON請求從MySQL數據庫中抓取一堆照片URL。一旦我有這些照片和相關信息,我用它來填充UITableView的數據源。我想創建一個UIButtons網格,由照片製成,每行4個。這個當前的代碼工作,但它非常慢,當我滾動桌子時,我的手機/模擬器凍結了。只有幾行的表格可以正常工作,但是一旦達到10行或更多行,就會減慢並接近崩潰。我是iOS和Objective-C的新手,所以我認爲這是代碼中的低效率。有什麼建議麼?謝謝!!在UITableView中處理UIButton Photo Grid的最有效方法是什麼?

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

回答

4

這很慢,因爲您在tableView:cellForRowAtIndexPath:中做了所有事情。 tableView:cellForRowAtIndexPath:被稱爲真的,尤其是每次需要在您的tableview中顯示一個單元格時,包括何時滾動您的tableView。因此,這種方法需要快速,和非阻塞(特別是不要做同步下載!)

而且你不正確地使用你的tableview單元格的可重用性。這會在每次爲每個單元重新創建內容(子視圖)時大幅降低性能。

  • 當你的電池是由前一個(把它看作是「再生」),你不能重做的一切,尤其是你絕不能每個子視圖重新添加,因爲已經是在細胞本身,再利用它已被重用,並不是一個乾淨的新的!
  • 而是,當dequeueReusableCellWithIdentifier:返回一個單元格(=舊的單元格以前創建但不再使用,因此您可以「回收」/重用它),您應該只更改每個單元格不同的內容。在您的示例中,通常您只會更改顯示的4個圖像,但不會重新創建UIImageView,既不會將它們添加爲子視圖(因爲這些子視圖已存在),也不會重新影響目標/操作。
  • 你只需要創建的UIImageView,增加他們的目標/行動,設置其框架,並將其添加爲一個子視圖,當你正在創造一個全新的細胞,具有alloc/initWithReuseIdentifier:/autorelease

而且,你取出由網絡的圖像直接在tableView:cellForRowAtIndexPath:,並同步在另外(這意味着它會阻止你的應用程序,直到它完成下載從網!!圖像)。 在您的tableView:cellForRowAtIndexPath:(例如當您的應用程序被加載時)執行異步下載並將其存儲在本地(例如在NSArray或sthg中)並僅在tableView:cellForRowAtIndexPath:中獲取本地已下載的映像。

如果您是iOS編程新手,那麼您嘗試執行的操作並不是最好的想法。你想要做什麼看起來很簡單,但它意味着像異步下載,應用程序的MVC設計等概念,並在你的視圖中顯示它們之前,從模型中的網絡中預取圖像,提供了一種在下載完成時更新tableview的方法,以及桌面視圖中單元重用的基本概念。

DO閱讀TableView Programming Guide繼續前進。它詳細解釋它,它真的值得一讀。 另請參閱Apple的LazyTableImages示例代碼,該代碼解釋瞭如何懶惰地加載圖像(意思是在需要時異步加載圖像)以及說明如何進行數據異步下載的URL Loading Programming Guide

這些指南和樣品是真的值得一讀,如果你想做你的解釋。在網上也有很多類的網格視圖,其中之一是我的作品(OHGridView),但在進一步研究之前,您需要首先了解上述和上述指南中的基本知識。

+0

非常棒的答案,非常感謝。我一定會給編程指南一個很好的閱讀和檢查你的課程。 – Eric

相關問題