【问题标题】:UITableView cell memory leakUITableView 单元格内存泄漏
【发布时间】:2012-01-30 17:55:46
【问题描述】:

我正在填充数据的表格视图中有泄漏。

这是发生了什么:

我有一个NSMutableArray 填充了NSDictionaries(联系信息),每次用户选择一个新的索引字母时,我都会从sql 数据库加载它,数组中填充了这些联系人的信息。

由于我使用实例变量数组来保存数据,因此在每次交换新数据之前,我都会想到这样的事情:

if (currentConnections != nil) {
    [currentConnections release];
    currentConnections = nil;
}

在我重置之前会有效地删除我的旧数据。
然而,这就是奇怪的开始。在我的tableView:cellForRowAtIndexPath: 中,我会这样打电话:

NSString *firstname = [[currentConnections objectAtIndex:indexPath.row]
                       objectForKey:@"firstname"];
UILabel *name = [[UILabel alloc]
                 initWithFrame:CGRectMake(75, 12, 190, 15)];
name.font = [UIFont fontWithName:@"Gotham-Medium.ttf" 
                            size:12];
name.textColor = [UIColor whiteColor];
name.backgroundColor = [UIColor clearColor];
name.text = firstname;

其中当前连接是字典数组。然后我将UILabel 添加为单元格的子视图:

[cell addSubview:name];
[name release];

这样的行为是这样的:

当我按原样运行时(在每次交换之前释放当前连接,然后将新数据加载到其中),应用程序将因访问错误而崩溃。
当我不释放我添加到单元格的子视图时,应用程序不会崩溃,但我惊恐地看到实时字节继续在内存分配工具中累积,直到我切换联系信息的程度足以我收到内存警告然后崩溃.

在我看来,单元格和子视图存在一些奇怪的内存所有权问题。我确实将单元格指定为可重用并在加载每个单元格数据之前将其分配给自动释放。

对可能导致此泄漏的原因有什么想法吗?

编辑:

这是当前的 tableView:cellForRowAtIndexPath:

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

static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

cell.accessoryType = UITableViewCellAccessoryNone;

if (cell == nil) {
    NSLog(@"within");
    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}

if (!ALOCATED) {


cellName = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(75, 12, 190, 15)
                 ];
cellName.font = [ UIFont 
             fontWithName:@"Gotham-Medium.ttf" 
             size:12 
             ];
cellName.textColor = [ UIColor whiteColor ];
cellName.backgroundColor = [ UIColor clearColor ];

NSString *firstname = [[ currentConnections 
                        objectAtIndex:indexPath.row 
                        ] objectForKey:@"firstname" 
                       ];

firstname = [ firstname stringByAppendingString:@" " ];

NSString *lastname = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"lastname" 
                      ];

UIImage *profPic = [[ currentConnections 
                     objectAtIndex:indexPath.row 
                     ] objectForKey:@"profilepicture" 
                    ];
connectionPhoto = [[ UIImageView alloc ] initWithFrame:CGRectMake(10, 8, 56, 56) ];
connectionPhoto.image = profPic;




NSString *fullname = [ firstname stringByAppendingString:lastname ];

cellName.text = fullname;


[ cell addSubview:cellName ];



cellTitle = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(75, 31, 260, 13)
                 ];
cellTitle.font = [ UIFont 
             fontWithName:@"ArialMT" 
             size:10 
             ];
cellTitle.textColor = [ UIColor whiteColor ];
cellTitle.backgroundColor = [ UIColor clearColor ];
cellTitle.text = [[ currentConnections 
                  objectAtIndex:indexPath.row 
                  ] objectForKey:@"title" 
                 ];


[ cell addSubview:cellTitle ];
[ cell addSubview:connectionPhoto ];
[ profPic release ];

    ALOCATED = YES;

} else {



    cellTitle.text = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"title" 
                      ];

    connectionPhoto.image = [[ currentConnections 
                                                             objectAtIndex:indexPath.row 
                                                             ] objectForKey:@"profilepicture" 
                             ];


    NSString *firstname = [[ currentConnections 
                            objectAtIndex:indexPath.row 
                            ] objectForKey:@"firstname" 
                           ];

    firstname = [ firstname stringByAppendingString:@" " ];

    NSString *lastname = [[ currentConnections 
                           objectAtIndex:indexPath.row 
                           ] objectForKey:@"lastname" 
                          ];
    NSString *fullname = [ firstname stringByAppendingString:lastname ];

    cellName.text = fullname;

}

return cell;

}

我试图创建一个单元格并重用它,每次只更改其子视图的属性。

编辑

发生的事情是我正在向单元对象本身添加子视图,这导致了泄漏,因为这些没有被释放。一旦我开始将视图添加到 UITableViewCell 成员视图,即 cell.contentView、cell.accessoryView 等......内存就被释放了。所以正如下面提到的丹尼尔,要么创建一个自定义表格单元格并将您的视图添加到您的单元格属性中,要么将您的视图添加到成员 uitablecellviews 而不是单元格本身。以下对我有用:

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

static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

cell.accessoryType = UITableViewCellAccessoryNone;

if (cell == nil) {

    cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}




UILabel *cName = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(105, 10, 190, 15)
                 ];
cName.font = [ UIFont 
             fontWithName:@"Gotham-Medium.ttf" 
             size:12 
             ];
cName.textColor = [ UIColor whiteColor ];
cName.backgroundColor = [ UIColor clearColor ];

NSString *firstname = [[ currentConnections 
                        objectAtIndex:indexPath.row 
                        ] objectForKey:@"firstname" 
                       ];

firstname = [ firstname stringByAppendingString:@" " ];

NSString *lastname = [[ currentConnections 
                       objectAtIndex:indexPath.row 
                       ] objectForKey:@"lastname" 
                      ];

NSString *fullname = [ firstname stringByAppendingString:lastname ];

cName.text = fullname;

[ cell.contentView addSubview:cName ];
[ cName release ];



cell.imageView.image = [[ currentConnections 
                     objectAtIndex:indexPath.row 
                     ] objectForKey:@"profilepicture" 
                    ];



UILabel *cTitle = [[ UILabel alloc ]
                 initWithFrame:CGRectMake(105, 25, 190, 13)
                 ];
cTitle.font = [ UIFont 
             fontWithName:@"ArialMT" 
             size:10 
             ];
cTitle.textColor = [ UIColor whiteColor ];
cTitle.backgroundColor = [ UIColor clearColor ];
cTitle.text = [[ currentConnections 
                  objectAtIndex:indexPath.row 
                  ] objectForKey:@"title" 
                 ];


[ cell.contentView addSubview:cTitle ];
[ cTitle release ];

return cell;

}

【问题讨论】:

  • 呃?如何将 NSString 添加为子视图
  • 我刚刚编辑了它。哎呀,这是我添加为子视图的标签

标签: iphone objective-c ios uitableview memory


【解决方案1】:

如果您正在重用单元格,并且每次设置单元格时都会向其添加 UILabel,那么您可以看到分配了多少 UILabel 可能会导致您的内存问题...如果您想添加标签到单元格,你应该只需要在分配它时执行一次,然后如果单元格作为重复使用的单元格进入,它已经包含你添加的 UILabel,所以你只需要编辑标签文本而不是添加新的 UILabel...这只是您发布的内容的猜测,更多代码可能会澄清一些事情...

问题在您发布的代码中很明显,您正在泄漏单元格实例变量,还请记住,cellForRowAtIndexPath 会为表中的每一行调用,因此保留一个实例变量以跟踪添加到的内容单元格将不起作用,var 将继续被覆盖,但在您的情况下,您正在泄漏单元格。您正在将单元格添加到 UITableViewCell,从不释放它们,然后在下一次调用 cellForRowAtIndexPath 时,单元格 var 被覆盖,并且前一个泄漏,因为您没有办法再释放它了......您可以通过释放单元格来解决这个问题...

现在您还遇到了使用一个 var 来跟踪单元格标签的问题,请记住,分配的不是一个单元格以供重复使用,它实际上是屏幕上可以显示的尽可能多的单元格,因此请保持跟踪一个 var 不起作用是你的问题......为了解决这个问题,我将 UITableViewCell 子类化为 label 属性并有一种方法来重置标签文本..

希望对你有帮助

【讨论】:

  • 这对我来说很有意义。我想我仍然不明白系统如何处理表格视图单元格。我尝试只分配第一次创建单元格时使用的标签和图像视图,然后只更新属性。但是,我的表格只显示了它的初始单元格,其余的都是空的。你有这种细胞重复使用的好模式的例子吗?
  • 张贴你的 cellforRowAtIndexPath,也许能看到你哪里出错了
  • 当您没有从 dequeueReusableCellWithIdentifier 中获得 nil 时,您知道单元格正在被重用,分配的逻辑是错误的,因为您只看到一行数据...cellForRowAtIndexPath 被调用一次每个部分中的行,如果您在第一个单元格之后将 alocated 设置为 TRUE,则不会设置任何其他单元格数据,但是从您发布的代码中可以看出泄漏问题...现在编辑答案
  • 还有一件事,当我初始化一个新单元时,我将它分配给自动释放,我是否还需要在其他地方释放这个单元?
  • 不,你泄漏的是标签,所以当你将标签添加到单元格时,单元格本身会保留它,但你在分配它时没有释放标签,因此泄漏跨度>
【解决方案2】:
  • 联系人太多,您无法将所有联系人都加载到同一个数组中?
  • 您可以使用 NSMutableArray 和方法 removeAllObjects。
  • 在您的代码中:

    [ 单元格 addSubview:firstname ]; firstname 是一个字符串...您不能将 NSString 添加为子视图...我建议创建一个自定义 UITableviewcell,因为单元格被回收,并且当您使用回收的单元格时,在他的创建过程中添加了所有子视图。

【讨论】:

  • 我在上面进行了编辑,我忘了提到我正在将文本分配给标签并将其添加为子视图。 removeAllObjects 似乎并没有摆脱分配的内存。所以现在我正在考虑使用自定义单元格。我仍然不确定为什么采用我的方法会导致额外的内存永远存在。有什么想法吗?
猜你喜欢
  • 2013-12-24
  • 1970-01-01
  • 2012-04-03
  • 2012-07-09
  • 2011-10-23
  • 2013-11-06
  • 2011-06-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多