cellForRowAtIndexPath内存管理

时间:2012-01-14 02:41:58

标签: iphone ios uitableview memory-management uikit

所以,这是我的cellForRowAtIndexPath的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier"];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"identifier"]autorelease];
    }

    NSInteger artistIndex = 1; // 1
    NSInteger albumIndex = 3;  // 3
    NSInteger dateIndex = 6;   // 6
    NSInteger imageIndex = 8;  // 5

    // ARTIST
    CGRect frame = CGRectMake(59, 11, 244, 13);
    UILabel *label = [[UILabel alloc]initWithFrame:frame];
    label.font = [UIFont boldSystemFontOfSize:13];
    label.textColor = [UIColor blackColor];
    label.text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:artistIndex];
    [cell addSubview:label];

    // ALBUM (more like description...
    frame = CGRectMake(60, 30, 244, 11);
    label = [[UILabel alloc]initWithFrame:frame];
    label.font = [UIFont boldSystemFontOfSize:11];
    label.textColor = [UIColor darkGrayColor];
    label.text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:albumIndex];
    [cell addSubview:label];

    // DATE
    frame = CGRectMake(59, 49, 244, 10);
    label = [[UILabel alloc]initWithFrame:frame];
    label.font = [UIFont fontWithName:@"Helvetica" size:10.0];
    label.textColor = [UIColor darkGrayColor];
    label.textAlignment = UITextAlignmentRight;
    label.text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:dateIndex];
    [cell addSubview:label];

    // IMAGE
    UIImageView *imageView = [[UIImageView alloc]init];
    imageView.image = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:imageIndex];
    imageView.frame = CGRectMake(8,9,44,44);
    [imageView.layer setMasksToBounds:YES];
    [imageView.layer setCornerRadius:3.0];
    [[cell contentView] addSubview:imageView];

    [imageView release];
    [label release]; 

    return cell;
}

为了解释发生了什么,基本上它只是点击一个存储除了索引8(存储UIImage)之外的所有内容的字符串的数组。

我没有设置自动释放的变量(主要是因为我真的不明白自动释放还是大声笑)

无论如何,当滚动应用程序时,它会逐渐减慢(主要是因为UIImage,但也部分是因为标签和框架)。

有没有更好地管理我的记忆?还有,有更好的编码方式吗?我正在考虑制作一个UITableViewCells数组,并通过cellForRowAtIndexPath访问它们。

所以我很想得到一些建议,谢谢你们。

5 个答案:

答案 0 :(得分:12)

你在那里泄露了很多标签。每次分配/初始化新标签时都需要释放它。目前,您通过为其分配新标签对象而不释放旧标签对象,多次重复使用相同的标签变量。

不要将[标签发布]放在最后,在每个[cell addSubview:label]之后放置[标签发布];

您的下一个问题是您误解了表格单元格的回收方式。 UITableCell对象在表中反复使用,这就是为什么这样做的原因:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier"];

if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"identifier"]autorelease];
}

这基本上是说"检查是否有可用的单元格,如果没有创建新的单元格"。重新使用单元格时,它会保留您添加的所有旧内容。因此,当您将这些标签和图像视图添加到单元格时,它们会在下次使用时保留在该单元格中,并在下次使用时保留在该单元格中。

但是因为每次重复使用单元格时都会再次添加标签,所以它会构建多个标签副本,因此第二次显示单元格时标签的数量是标签的两倍,下一次是标签的3倍很多,等等。您无法看到重复项,因为它们位于完全相同的位置,但它们会耗尽内存并降低您的桌面速度。

您需要移动代码,将新视图附加到" if(cell == nil){...}"声明,因此标签只在创建单元格时添加一次。

当然这意味着每个单元格都有相同的文本和图像,这是您不想要的,因此您需要拆分设置文本和图像的逻辑,并将其放在if语句之后。这样您只需创建一次标签,但每次在不同的表格行中显示时都会设置文本。这有点棘手,因为您不再拥有对标签的引用,但您可以通过在标签上设置唯一标记来实现,这样您就可以再次找到它们。

这是一个清理过的版本,并删除了所有泄漏:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"identifier"];

    NSInteger artistTag = 1;
    NSInteger albumTag = 2;
    NSInteger dateTag = 3;
    NSInteger imageTag = 4;

    if (cell == nil) {

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"identifier"]autorelease];

        // ARTIST
        CGRect frame = CGRectMake(59, 11, 244, 13);
        UILabel *label = [[UILabel alloc]initWithFrame:frame];
        label.font = [UIFont boldSystemFontOfSize:13];
        label.textColor = [UIColor blackColor];
        label.tag = artistTag;
        [cell addSubview:label];
        [label release];

        // ALBUM (more like description...
        frame = CGRectMake(60, 30, 244, 11);
        label = [[UILabel alloc]initWithFrame:frame];
        label.font = [UIFont boldSystemFontOfSize:11];
        label.textColor = [UIColor darkGrayColor];
        label.tag = albumTag;
        [cell addSubview:label];
        [label release];

        // DATE
        frame = CGRectMake(59, 49, 244, 10);
        label = [[UILabel alloc]initWithFrame:frame];
        label.font = [UIFont fontWithName:@"Helvetica" size:10.0];
        label.textColor = [UIColor darkGrayColor];
        label.textAlignment = UITextAlignmentRight;
        label.tag = dateTag;
        [cell addSubview:label];
        [label release];

        // IMAGE
        UIImageView *imageView = [[UIImageView alloc]init];
        imageView.frame = CGRectMake(8,9,44,44);
        imageView.tag = imageTag;
        [imageView.layer setMasksToBounds:YES];
        [imageView.layer setCornerRadius:3.0];
        [[cell contentView] addSubview:imageView];
        [imageView release];
    }

    NSInteger artistIndex = 1; // 1
    NSInteger albumIndex = 3;  // 3
    NSInteger dateIndex = 6;   // 6
    NSInteger imageIndex = 8;  // 5

    ((UILabel *)[cell viewWithTag:artistTag]).text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:artistIndex];

    ((UILabel *)[cell viewWithTag:albumTag]).text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:albumIndex];

    ((UILabel *)[cell viewWithTag:dateTag]).text = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:dateIndex];

    ((UIImageView *)[cell viewWithTag:imageTag]).image = [[musicList.list objectAtIndex:indexPath.row] objectAtIndex:imageIndex];


    return cell;
} 

答案 1 :(得分:5)

为了提高内存使用效率并获得更流畅的滚动性能,您应该创建一个自定义UITableViewCell子类,其中包含一个自定义UIView作为UITableViewCell的contentView的子视图。您应该使用 -drawRect:在此自定义视图上绘图。拥有一个大视图层次结构是非常占用大量内存的,而不是只有一个视图直接在其上绘制所有内容。

Apple的TableViewSuite示例实际上包含了这种直接绘图方法的示例。在这里下载项目:

http://developer.apple.com/library/ios/#samplecode/TableViewSuite/Introduction/Intro.html

查看第五个示例,了解如何在您自己的项目中实现高性能,低内存自定义tableview单元格绘制。

答案 2 :(得分:0)

为什么不在IB和子类UITableViewCell中构建你的单元来根据你的需要定制它(3个UILabels和一个UIImageView)?我有复杂的tableview单元设计,这个系统适合我。使代码更清晰,更易于管理。如果你需要一个有效的例子,我可以发给你。

答案 3 :(得分:0)

尝试设置静态字符串并在以下方法中使用:

    static NSString *identifier = @"identifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil) {
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:identifier]autorelease];

答案 4 :(得分:0)

总之,泄漏原因是addSubview的额外引用。 所以确保addSubview一次或删除它之后再添加新的。