【问题标题】:viewForHeaderInSection creating a memory leak?viewForHeaderInSection 创建内存泄漏?
【发布时间】:2011-08-20 15:10:38
【问题描述】:

我在使用自定义标题视图和委托方法 tableView:viewForHeaderInSection: 获得我想要的外观方面取得了巨大成功。但我认为它正在产生内存泄漏,我不知道该怎么办。

代码是这样的:

- (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    NSLog (@"New header, section %d", section);
    ResultsHeaderView *header = [[ResultsHeaderView alloc] initWithFrame:CGRectMake(0, 0, defaultResultsHeaderSize.width, defaultResultsHeaderSize.height)];

    SearchResult *result = [[[[self.fetchedResultsController sections] objectAtIndex:section] objects] objectAtIndex:0];

    header.text = result.searchUsed.keywords;
    header.searchTermsEntity = result.searchUsed;
    header.resultDelegate = self;
    header.section = section;

    return [header autorelease];
}

如你所见,每次调用this都会实例化一个ResultHeaderView类型的新对象,它是UIView的子类。

问题是它经常被调用,每次一个节标题从视图中滚动出来然后又重新打开时,它就会被调用。添加新部分时,它会被多次调用,即使对于其他部分也是如此(尽管我可能对此有一些控制,我将对其进行研究。)

我想知道是否有类似 tableView:dequeueReusableCellWithIdentifier: 可以管理节标题视图,或者知道何时需要发布节标题视图的方法。我不确定自动释放是否足以避免泄漏。

同时,我的理解是创建单元格的成本很高,这就是为什么它们可以通过 dequeueReusableCellWithIdentifier 进程重用。我不得不想象这与节标题相同。

有谁在评论之前遇到过这个问题吗?

【问题讨论】:

    标签: objective-c uitableview custom-controls sectionheader


    【解决方案1】:

    这是我决定做的事情,除非有人能看出其中的缺陷或能想出更好的主意。

    在管理tableView的视图控制器中,我添加了一个属性

    NSMutableArray *viewsForSectionHeaders;
    

    然后我修改了我的 tableView:viewForHeaderInSection:

    - (UIView *) tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    
        SearchResult *result = [[[[self.fetchedResultsController sections] objectAtIndex:section] objects] objectAtIndex:0];
    
        ResultsHeaderView *header;
    
        if (section < [viewsForSectionHeaders count]) {
            header = [viewsForSectionHeaders objectAtIndex:section];
        }
        else {
            header = [[[ResultsHeaderView alloc] initWithFrame:CGRectMake(0, 0, defaultResultsHeaderSize.width, defaultResultsHeaderSize.height)] autorelease];
            [viewsForSectionHeaders addObject:header];
        }
    
        header.text = result.searchUsed.keywords;
        header.searchTermsEntity = result.searchUsed;
        header.resultDelegate = self;
        header.section = section;
    
        return header;
    }
    

    在这种情况下,我有一个标题视图数组。这不是很明显,但是每当更新 fetchedResultsController 时,它可能会“不匹配”先前关联的标头与它们最初匹配的不同部分。但这并不重要,因为标题属性(文本、searchTermsEntity、resultDelegate 和部分)都在上面的代码中重置。

    所以,在我看到我错过的东西之前,这看起来像是只在需要时实例化标题视图,并重用已经创建的那些。

    (请注意,我将 autorelease 移到了分配视图的位置。我在引用 nil 对象时遇到了一个错误,这修复了它。另外,现在我想到了,在 return 中设置了 autorelease如果在之前对该代码的调用中实例化了一个对象,语句将多次重复该对象的自动释放。我不知道这是否是一个真正的问题,但是当我在它的时候,很容易解决这个问题.)

    现在,我不删除部分,所以我不必担心释放标题视图。但是如果我确实删除了部分,那么这意味着标题视图也应该从 viewsForSectionHeaders 数组中删除。

    【讨论】:

    • 看起来是一个明智的解决方法,我自己没有尝试过代码,但阅读它我唯一的评论是似乎做出了一个假设(这可能是一个合理的假设)表视图将始终以正确的顺序请求节标题(即,它永远不会在 3 之前请求节标题 4 等),如果它曾经请求它们乱序(我不知道它会不会)我认为您的代码可能会失败。尝试快速滚动表格视图,看看是否可以“跳过”一个部分,看看是否会导致问题。
    【解决方案2】:

    一遍又一遍地创建视图在 CPU 方面可能是相当昂贵的,尽管我没想到它会泄漏(我以前使用过这种技术时从未注意到泄漏)。

    另一种解决方案(我以前自己使用过的解决方案)是创建一种不同类型的自定义单元格,该单元格可以具有不同的单元格标识符,并且可以根据需要出列和重用 - 然后将其用作标题,因此每个部分的第 0 行实际上是您的部分标题,而真正的行实际上从第 1 行开始。

    【讨论】:

    • 谢谢,理查德。我考虑过这种方法。在这种情况下,我更喜欢使用节标题。
    • 出色的解决方法。我发现自定义 viewForHeaderInSection 至少会花费我 5fps,因为 tableView 每次都会调用它。糟透了。苹果应该解决这个问题。但在那之前,您的解决方案非常棒。
    • @Jason,感谢您的积极反馈,这种方法的唯一缺点是当使用普通样式时,标题不会“浮动”在屏幕顶部,直到该部分完全滚动最重要的是——我个人不喜欢这样,但值得一提。
    猜你喜欢
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2018-11-28
    • 2014-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多