2013-02-04 163 views
0

我的應用程序的其中一個視圖顯示圖像列表。當我滾動列表多次,然後我的應用程序崩潰。我用儀器對它進行了分析,似乎列表滾動時列表中的單元格佔用更多內存。iOS:在滾動UITableView時填充應用程序崩潰/內存

當從tableView:cellForRowAtIndexPath:返回時,自定義的UITableCell應該是'autoreleased'嗎? (如果我這樣做,我的iOS 4.3崩潰/在iOS 5.0和6.1中很好)

這個自定義UITableCell有幾張圖片被繪製到它的'contentView'中。這些圖片實際上是自定義的UIButton,我在其中設置了背景圖片。

的圖像與自定義的UIButton HJManagedImageV

代碼管理:自定義單元格

@implementation ProductGridCellIpad 

@synthesize products, parentController; 

- (void)initializeWithProducts:(NSMutableArray *)productsToShow{ 

    self.products = productsToShow; 

    // clear possible old subviews 
    for (UIView *v in self.contentView.subviews) { 
     [v removeFromSuperview]; 
    } 

    NSInteger width = 240; 
    NSInteger height = 240; 

    Product *product0 = [products objectAtIndex:0]; 

    self.productTile0 = [[[ProductTileButtonIpad alloc] initWithFrame:CGRectMake(12, 12, width, height) andProduct:product0] autorelease]; 

    [self.productTile0 addTarget:self.parentController action:@selector(selectedProduct:) forControlEvents:UIControlEventTouchUpInside]; 

    [self.contentView addSubview:self.productTile0]; 

    [self.productTile0 release]; 

    if ([self.products count] > 1) { 

     Product *product1 = [products objectAtIndex:1]; 

     self.productTile1 = [[[ProductTileButtonIpad alloc] initWithFrame:CGRectMake(12 + width + 12, 12, width, height) andProduct:product1] autorelease]; 

     [self.productTile1 addTarget:self.parentController action:@selector(selectedProduct:) forControlEvents:UIControlEventTouchUpInside]; 

     [self.contentView addSubview:self.productTile1]; 

     [self.productTile1 release]; 
    } 

    if ([self.products count] > 2) { 

     Product *product2 = [products objectAtIndex:2]; 

     self.productTile2 = [[[ProductTileButtonIpad alloc] initWithFrame:CGRectMake(2*(12 + width) + 12, 12, width, height) andProduct:product2] autorelease]; 

     [self.productTile2 addTarget:self.parentController action:@selector(selectedProduct:) forControlEvents:UIControlEventTouchUpInside]; 

     [self.contentView addSubview:self.productTile2]; 

     [self.productTile2 release]; 
    } 
} 

- (void)dealloc { 

    NSLog(@"deallocating ProductGridCellIpad"); 

    if(self.products) 
     [self.products release]; 

    if(self.productTile0) 
     [self.productTile0 release]; 

    if(self.productTile1) 
     [self.productTile1 release]; 

    if(self.productTile2) 
     [self.productTile2 release]; 

    [super dealloc]; 
} 

@end 

這裏

@implementation ProductTileButtonIpad 

@synthesize product; 

- (id)initWithFrame:(CGRect)frame andProduct:(Product *)aProduct { 

    if (self = [super initWithFrame:frame]) { 

     self.product = aProduct; 

     self.productTileView = [[[HJManagedImageV alloc] initWithFrame:self.frame] autorelease]; 
     self.productTileView.callbackOnSetImage = self; 
     self.productTileView.url = some picture url 

     [[ImageManager instance] manage:self.productTileView]; 
    } 

    return self; 
} 


#pragma mark - 
#pragma mark HJManagedImageV delegate 

-(void) managedImageSet:(HJManagedImageV*)mi { 

    [self setBackgroundImage:mi.image forState:UIControlStateNormal]; 
} 

-(void) managedImageCancelled:(HJManagedImageV*)mi { 
} 


- (void)dealloc { 

    NSLog(@"deallocating ProductTileButtonIpad"); 

    [self.product release]; 
    [self.productTileView release]; 

    [super dealloc]; 
} 

@end 

代碼是一個創建單元代碼:

NSString *productGridCellIpadIdentifier = @"ProductGridCellIpadIdentifier"; 

    ProductGridCellIpad *cell = [tableView dequeueReusableCellWithIdentifier:productGridCellIpadIdentifier]; 

    if(cell == nil) { 

     cell = [[ProductGridCellIpad alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:productGridCellIpadIdentifier]; 

     [cell setFrame:CGRectMake(0, 0, self.view.frame.size.width, 244)]; 
    } 

    [cell setParentController:self]; 
    [cell initializeWithProducts:products]; 

    return cell; 

因爲現在代碼在iOS 4.3上立即崩潰。它適用於iOS 5和iOS 6,但在使用/滾動表格一段時間後,應用程序仍會崩潰。

我不使用ARC。

我加了一些的NSLog在dealloc的方法,看看發生了什麼,我可以看到很多「重新分配ProductTileButtonIpad」但我從來沒有看到「重新分配ProductGridCellIpad」

我的應用程序很容易達到400MB的內存使用。

我在這裏做錯了什麼?

如果某些您有任何想法,意見,可以幫助我的理解,將不勝感激:)

+0

不知道是不是這樣,但如果您不使用ARC,則需要自動釋放單元格。 – 2013-02-04 07:59:20

+1

問題是你每次初始化的東西,你應該只進行一次初始化..當你使用tableview if(cell == nil){//你初始化的時候它是這樣的// //這裏只更新值..在這裏沒有初始化.. – iphonic

+0

@iphonic你是什麼意思的「你每次初始化的東西」?因爲我確實使用細胞回收... – Alexis

回答

2

細胞被重用,所以你不應該看到「的dealloc ProductGridCellIpad」滾動時。相反,請驗證回收是否真的有效,或者您是否始終創建新單元格:

ProductGridCellIpad *cell = [tableView dequeueReusableCellWithIdentifier:productGridCellIpadIdentifier]; 

if(cell == nil) { 
    cell = [[ProductGridCellIpad alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:productGridCellIpadIdentifier]; 
    [cell setFrame:CGRectMake(0, 0, self.view.frame.size.width, 244)]; 
    NSLog("Cell created"); 
} 
else { 
    NSLog("Cell recycled"); 
} 

如果沒關係,我會檢查發佈。例如,你有「self.productTile2」autorelease和release,這可能會混淆內存管理。

另外我會仔細檢查「parentController」,這可能會阻止事情被釋放。你需要將它設置爲零。

+0

回收似乎很好:4個單元格被創建(我猜這是因爲4個單元格在屏幕上可見),然後它們都被回收,但如果我回到前一個視圖然後再次顯示列表,我可以看到4個新的細胞創建。所以如果我一直這樣做,內存使用量會增加嗎? – Alexis

+0

關於釋放我應該怎麼做,然後在目前的情況下?發佈或autorelease?我沒有真正瞭解它們之間的區別,除了在我調用release之後無法觸摸ref ... – Alexis

+0

使用autorelease(當系統在對象沒有被使用後再釋放)或者使用釋放(當你告訴系統對象已準備好在下次釋放時釋放)但不要同時使用兩者。 – JOM

1

是的,你顯然必須使用autorelease你的手機使用時alloc] init.. dequeueReusableCellWithIdentifier返回自動釋放一個。