0

私のアプリのビューの 1 つに、画像のリストが表示されます。そのリストを数回スクロールすると、アプリがクラッシュします。リストをスクロールすると、リストのセルがより多くのメモリを消費しているようです。

tableView:cellForRowAtIndexPath: から返されたときにカスタム UITableCell を「自動解放」する必要がありますか? (そうすると、iOS 4.3 でクラッシュします / iOS 5.0 および 6.1 では問題ありません)

このカスタム UITableCell には、その「contentView」に描画されたいくつかの画像があります。これらの写真は、実際には背景画像を設定したカスタム UIButton です。

イメージはHJManagedImageVで管理されます

カスタム UIButton のコード:

@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

カスタムセルのコード

@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

セルを作成するコードは次のとおりです。

    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 および 6 で動作しますが、テーブルを一定時間使用またはスクロールするとアプリがクラッシュします。

ARCは使いません。

何が起こっているかを確認するために、dealloc メソッドに NSLog を追加しました。「ProductTileButtonIpad の割り当て解除」がたくさん表示されますが、「ProductGridCellIpad の割り当て解除」は表示されません。

私のアプリは簡単に 400Mb のメモリ使用量に達します。

ここで何が間違っていますか?

あなたの何人かが何か考えを持っているなら、私の理解を助けることができるアイデアは大歓迎です:)

4

2 に答える 2

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」を注意深くチェックすると、リリースが妨げられる可能性があります。nil に設定する必要があります。

于 2013-02-04T08:03:42.800 に答える
1

はい、自動リリースされた返品を使用する場合は、明らかにautoreleaseセルに移動する必要があります。alloc] init.. dequeueReusableCellWithIdentifier

于 2013-02-04T09:37:19.893 に答える