是dequeueReusableCellWithIdentifier强制避免内存泄漏?

时间:2012-03-06 21:24:47

标签: ios uitableview

我使用几乎每个人都用来处理cellForRowAtIndexPath的“着名”样板代码:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"someCustomCellID"];  
if (cell == nil)  // nothing to recycle from the queue: create a new cell

但这给了我很多问题'因为我的单元格包含我加载异步的图像,并且两个功能(出列和异步加载)经常发生冲突。因此,我尝试每次创建一个新单元格,并且它的工作非常好而且速度很快。 但我有一个疑问:即使我忽略返回的值并每次都创建单元格,我是否还应该调用dequeueReusableCellWithIdentifier来释放内存? 我想不再使用的单元格会被自动释放(因为它们应该是),但是我想知道缓存队列是否需要使用dequeue调用显式“free”...

5 个答案:

答案 0 :(得分:4)

dequeueReusableCellWithIdentifier并非旨在防止内存泄漏,但它是为性能而设计的(一种方法是减少内存使用)。使用dequeue方法时,如果有多行数据,滚动表视图会更加平滑。我建议您使用异步加载来使用dequeue方法,特别是如果您在滚动时看到任何延迟。如果您想了解如何执行此操作的示例,请参阅Apple's LaxyTableImages Example。但是,如果确实这样做,确定您不想重复使用单元格,那么在创建单元格时只需将nil作为reuseIdentifier传递。

答案 1 :(得分:2)

dequeueReusableCellWithIdentifier有助于减少从文件或XIB加载重新加载内容的次数。如果您有自定义单元格或具有非标准内容的单元格,则重新使用已经全部设置的单元格可以快得多。

我记得在类似的事情上工作,但在我们的例子中,我们异步地将图像加载到Core Data对象中,并让单元格观察该对象中的图像。加载图像后,会通知单元格并更新其图像视图。

当细胞通过dequeueReusableCellWithIdentifier返回给我们时,我们停止观察并将其设置为观察下一个物体的图像。

答案 2 :(得分:2)

只需在prepareForReuse:类中使用UITableViewCell,即可在重新使用单元格之前停止异步加载。

答案 3 :(得分:0)

是的,如果要动态分配单元格,则需要使用dequeueReusableCellWithIdentifier来避免泄漏。

大概你的异步图像加载是这样的:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (!cell) {
        ...
    }

    NSURLRequest *request = [self URLRequestForIndexPath:indexPath];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
        completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
            cell.imageView.image = [UIImage imageWithData:data];
        }];

    return cell;
}

该代码存在问题。在完成处理程序运行时,表视图可能已将该单元格重用于另一行!

我们需要更改完成块,以便在准备好设置图像时查找该行的单元格:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (!cell) {
        ...
    }

    NSURLRequest *request = [self URLRequestForIndexPath:indexPath];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue]
        completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
            UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
            if (cell)
                cell.imageView.image = [UIImage imageWithData:data];
        }];

    return cell;
}

答案 4 :(得分:0)

您应该始终使用该方法。如果它返回一个单元格,请使用该单元格。如果它返回nil,则只有这样才能创建一个单元格。

如果该方法要求您还没有加载图像的单元格,那么您应该提供替代方法。也许UIImageView带有定制的动画进度微调器?然后,当您的图像到达时,您可以在必要时使用正确的图像。

不要担心释放细胞。一旦你将它们提供给表视图,它们就是表视图的责任(至少就内存管理而言)。

相关问题