简体   繁体   English

iOS:滚动UITableView时,应用程序崩溃/内存已满

[英]iOS : app crash / memory is filled in when scrolling a UITableView

One of the views od my app shows a list of images. 我的应用程序中的其中一种视图显示了图像列表。 When I scroll that list several times then my app crashes. 当我滚动列表几次后,我的应用程序崩溃了。 I profiled it with instrument and it seems that the cells of the list are taking more memory as the list is scrolled. 我用仪器对其进行了分析,并且随着列表的滚动,列表的单元格似乎占用了更多的内存。

Should a custom UITableCell be 'autoreleased' when returned from tableView:cellForRowAtIndexPath: ? 从tableView:cellForRowAtIndexPath:返回时,自定义UITableCell是否应“自动释放”? (if I do, I have a crash on iOS 4.3 / it's fine in iOS 5.0 and 6.1) (如果这样做,我在iOS 4.3上崩溃了/在iOS 5.0和6.1中都可以)

This custom UITableCell have several pictures drawn into its 'contentView'. 此自定义UITableCell的“ contentView”中绘制了几张图片。 Those pictures are actually custom UIButton in which I set the background image. 这些图片实际上是我在其中设置背景图片的自定义UIButton。

The images are managed with HJManagedImageV 图像由HJManagedImageV管理

code for custom UIButton : 自定义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

code for the custom cell 自定义单元格的代码

@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

and here's the code that creates the cell : 这是创建单元格的代码:

    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;

As it is now the code crashes right away on iOS 4.3. 现在,代码立即在iOS 4.3上崩溃。 It works on iOS 5 and 6 but the app still crashes after a certain time of use/scrolling the table. 它可以在iOS 5和6上运行,但在使用/滚动表格一定时间后,该应用仍会崩溃。

I don't use ARC. 我不使用ARC。

I added some NSLog in the dealloc methods to see what's happening and I can see lots of "deallocating ProductTileButtonIpad" but I never see "deallocating ProductGridCellIpad" 我在dealloc方法中添加了一些NSLog,以查看发生了什么,并且可以看到很多“正在分配ProductTileButtonIpad”,但从未看到“正在分配ProductGridCellIpad”

My app easily reaches memory usage of 400Mb. 我的应用很容易达到400Mb的内存使用量。

What am I doing wrong here? 我在这里做错了什么?

If some of you have any thoughts, ideas that could help my understanding it would be much appreciated :) 如果你们中有人有什么想法,可以帮助我理解的想法,将不胜感激:)

Cells are reused, so you shouldn't see "dealloc ProductGridCellIpad" when scrolling. 单元已被重用,因此滚动时不应看到“ dealloc ProductGridCellIpad”。 Instead verify whether recycling really is working or whether you keep creating new cells all the time: 相反,请验证回收是否确实有效或是否一直在不断创建新单元:

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");
}

If that's ok, I'd check releasing. 如果可以,我会检查释放。 For example you have "self.productTile2" both autorelease and release, which might confuse memory management. 例如,您同时具有自动释放和释放功能“ self.productTile2”,这可能会使内存管理混乱。

Also I'd check carefully the "parentController", which might prevent things from being released. 另外,我会仔细检查“ parentController”,这可能会阻止发布内容。 You need to set it to nil. 您需要将其设置为nil。

是的,当使用alloc] init..时,您显然必须autorelease单元格dequeueReusableCellWithIdentifier返回自动autorelease的单元格。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM